pytest的介绍与使用

pytest介绍

pytest整合了unittest,包含了unittest中的方法,并且比其更轻便快捷,而且结合Allure报告能够清晰的生成测试报告。
1、安装:
pip install pytest
2、测试文件:
test_*.py
_test.py
3用例识别:
Test
类包含的所有的test_*的方法(测试类不能带有init方法)
不在class中的所有test_*方法
pytest也可以执行unittestu昂加写的用例和方法

终端执行

pytest 文件名
pytest py_test.py
参数:
-v
-s
::类名
::类名::方法名

pytest py_test.py::Testdemo2

-k
pytest -k 文件名 “类名 and not 方法名” —跳过

pytest  py_test.py  -k "TestDemo1 and not 

test_one"@skip()
pytest -m [标记名] @pytest.mark[标记名]
pytest -x 文件名 —一旦运行到报错就停止运行
pytest --maxfail=[num] 错误数目,如果错误数目达到

    pytest执行-失败重新运行

场景:
1、测试过程中,可能有弹框、网络错误导致加载失败,可以通过失败重新执行来做
2、安装:
pip install pytest-rerunsfailuers
3、执行:
pytest --reruns 3 -v -s test_class.py
pytest -v --ruruns 5 -reruns-delay 1#增加时间间隔

安装断言所需要的库
pip install pytest-assume
pytest.assume(判断表达式)
pytest py_test.py::TestDemo2::test_two

执行方法:
pychrm中配置为pytest
mian方法中:pytest.main("-v -x TestDemo")

pytest的架构

在这里插入图片描述
优先级:(高->低)
setup_module:在所有的方法执行之前执行
setup_class:在这个类的执行之前执行
setup_function:类外部方法
setup_method:
setup

pytest-fixture

fixture 的功能 主要包括以下三点:
传入测试中的数据集
配置测试前系统的初始状态,
为批量测试提供数据源

pytest-fixture的用法

在这里插入图片描述
fixture用来解决很多测试方法的前置条件不一样,无法用setup解决这种不同的时候,使用
@pytest.fixture 加在我们所需的前置条件的方法上,以参数名的形式传给所需要的测试方法
fixture可以用作,参数中可以传入方法

class TestDemo1:
    @pytest.fixture()
    def test_login(self):
        print("这是一个登陆方法")
    def test_one(self,test_login):
        print("1需要登录 test_one")
    def test_two(self):
        pytest.assume( 1 == 2)
        print("test_two")
    def test_three(self,test_login):
        pytest.assume( 1 == 2)
        print("3需要登录test_three")
        '''
        结果:在每个添加前置方法的测试方法前,执行了这个方法
py_test.py::TestDemo1::test_one 这是一个登陆方法
1需要登录 test_one
PASSED
py_test.py::TestDemo1::test_two test_two
FAILED
py_test.py::TestDemo1::test_three 这是一个登陆方法
3需要登录test_three
FAILED
'''

fixture()函数中的参数

在这里插入图片描述

scope作用域

在这里插入图片描述
应用的范围默认为function,类似于setup和teardown中作用域的方法

fixture的自动应用

在这里插入图片描述
就是让我们标记的前置方法以及后置方法,不通过测试方法中添加方法函数名,而是自动应用到这个模块下的所有方法中:

class Test_fixtures:
    @pytest.fixture(scope="function", autouse=True)  # 只调用一次
    def open(self):
        print("打开浏览器")
        yield  # 之前的操作,相当于setup,之后的操作,相当于teardown的操作
        print("执行teardown")
        print("最后关闭浏览器")
    def test_search1(self):
        print("test_search1")
    #raise NameError

    def test_search2(self):
        print("test_search2")


if __name__ == '__main__':
    pytest.main("-v -s")
    
'''
结果:
test_fixture.py 打开浏览器
.test_search1
执行teardown
最后关闭浏览器
打开浏览器
.test_search2
执行teardown
最后关闭浏览器'''

数据共享文件conftest

那么我们的login方法在开发时其实需要放在一个公共的地方,哪里需要,放在哪里,其实可以将他从这个模块中拿出来,放在一个公共的地方:首选conftest.py文件
conftest.py文件非常重要,是pytest提供的特殊的进行数据共享的文件,执行到login方法时时,先从本模块中找,如果则执行,没有则找该文件,有则执行,无则报错。
注意:
1、conftest文件名不能更换
2、conftest要和执行的文件放在同一个package下

在这里插入图片描述

import pytest
@pytest.fixture(scope="module")#只调用一次
def open():
    print("打开浏览器")
    yield
    #之前的操作,相当于setup,之后的操作,相当于teardown的操作
    print("执行teardown")
    print("最后关闭浏览器")


def test_search1(open):
    print("test_search1")
    raise NameError
    pass
def test_search2(open):
    print("test_search2")
    pass

if __name__ == '__main__':
    pytest.main("-v -s")
    

pytest测试数据参数化

在这里插入图片描述
先来看下params的定义

:param params:
        An optional list of parameters which will cause multiple invocations
        of the fixture function and all of the tests using it. The current
        parameter is available in ``request.param``.

参数必须使用request.param返回

import pytest

@pytest.fixture(params=("one","two"), scope='function', autouse=False)
def search1(request):
    print("test_search1")
    print(type(request.param))
    return request.param

def test_search1(search1):
    print(f"{search1}")
    
 '''
 test_fixture01.py test_search1
<class 'str'>
.one
test_search1
<class 'str'>
.two
'''

传参的方式可以使用@pytest.mark.parameterize(“参数名”,data)
这种方式使用起来更加灵活
举个栗子:判断输入与期望值是否一致

@pytest.mark.parametrize("test_input,expected",[("2+1",3),("2+9",11),("2+5",9)])
def test_search1(test_input,expected):
    #eval()将字符串转化为数值的表达式
    pytest.assume(eval(test_input) == expected)

上面的方法是将所有的组合罗列出来,下面这个方法是将单个参数的值罗列出来,会自己去组合,效果和自己组合的是一样的

@pytest.mark.parametrize('test_input',["2+1","2+9"])
@pytest.mark.parametrize('expected',[3,8])
#@pytest.mark.parametrize("test_input,expected",[("2+1",3),("2+9",11),("2+5",9)])
def test_search1(test_input,expected):
    #eval()将字符串转化为数值的表达式
    pytest.assume(eval(test_input) == expected)

pytest将方法作为参数

测试方法中,参数为方法名,indirect=True时,将参数作为该方法的返回值,传入测试方法中

import pytest
#方法名作为参数
data = {'user1','user2'}
@pytest.fixture(scope='module')
def login_r(request):
    #接收传入的参数
    user = request.param
    print(f'\n打开登录页准备登录,登录用户:{user}')
    return user
#这里将login_r作为测试方法的参数,主要是参数indirect=True起作用,默认情况是不把方法名作为一个方法的
@pytest.mark.parametrize('login_r',data,indirect=True)
def test_login_r(login_r):
    a = login_r
    print(f'测试用例的返回值为:{a}')
    assert a != ""

pytest跳过某一部分测试用例

跳过某条用例
@pytest.mark.skip(“此次不执行这条用例先跳过”,reason=“不执行原因是”)
2、特定的判断条件下不执行这条用例,并写明原因:
@pytest.mark.skip(sys.plantform == 2.5,reason=“不执行原因是”)
3、不跳过加标注的方式以pass的结果不执行某条用例
@pytest.mark.xfail
总结:
在这里插入图片描述

使用自定义标记mark只执行某部分的测试用例

在这里插入图片描述

import pytest
#将模块归类
@pytest.mark.search
def test_search1():
    print("test_search1")
    raise NameError
    pass

@pytest.mark.search
def test_search2():
    print("test_search2")
    pass

def test_search3():
    print("test_search3")
    pass

@pytest.mark.login
def test_login1():
    print("test_login1")
    pass

@pytest.mark.login
def test_login2():
    print("test_login2")
    pass

terminal中输入 pytest -s
在这里插入图片描述
pytest -s q.py -n 4
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值