python测试---pytest使用 fixture、mark

本文详细介绍了pytest框架的优势,包括其简单灵活的特性、参数化支持和错误处理。深入讲解了fixture的使用,如登录场景、conftest文件、yield语法以及自动应用。此外,还阐述了mark的参数化测试、skip和xfail标记,以及如何自定义标记执行部分用例。最后,探讨了多线程并行和分布式执行以及pytest生成测试报告的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

pytest框架的优势

  • 简单灵活,容易上手;支持参数化; 测试用例的skip和xfail处理;
  • 能够支持简单的单元测试和复杂的功能测试,还可以做selenium/appnium等自动化测试、接口自动化测试(pytest+requests);
  • pytest具有很多第三方插件,并且可以自定义扩展, 较好的如pytest-allure(完美html测试报告生成)、pytest-xdist(多 CPU分发)等;
  • 可以很好的和jenkins集成;

pytest框架的规范

  • 首先要import pytest
  • 与Unittest使用方法相同的setUp和tearDown
  • 在命令行中,可以使用如下命令:
    pytest --v(最高级别信息)
    pytest -v -s 文件名(带控制台输出结果)
  • 测试文件名称以 test_ 开头(以 _test 结尾也可以)
  • 测试类名称以 Test 开头,并且不能带有 init 方法
  • 测试方法名称以 test_ 开头

测试文件的运行

import pytest

pycharm运行

在main下
pytest.main([’-s’,‘文件名’])

控制台运行

pytest -s 文件名

前端自动化应用

登录

  • 场景:测试用例执行时,有些需要登录执行,有些不需要
  • 在登录函数前加@pytest.fixture(),需要登录的在测试方法中传入登录函数,范围默认函数级别
@pytest.fixture()
def login():
    print('login')
def test_l(login):
    print('case1:l')
def test_nl():
    print('case2:nl')

if __name__=='__main__':
    pytest.main(['-s','test_fitt.py'])

conftest

在这里插入图片描述

yield

  • 场景:测试方法后销毁清除数据,范围是模块级别,类似setupClass
  • 在同一模块中加入yield关键字,第一次调用返回结果,第二次执行yield后面的语句
  • 在登录方法中加yield,之后加销毁清除的步骤
  • 希望返回值使用addfinalizer

fixture的自动应用

  • 场景:不想原测试方法有任何改动,或全部都自动实现自动应用,没有特例,也不需要返回值
  • @pytest.fixture(autouse=true)
  • @pytest.mark.usefixtures(‘自动实现的函数’)
@pytest.fixture(scope='module',autouse=True)#一整段都自动应用
def open_browser():
    print('dakai ')
    yield
    print('teardown')
    print('guanbi')

@pytest.fixture()
def login():
    print('login')
def test_l(login):
    print('case1:l')
def test_nl():
    print('case2:nl')
if __name__ == '__main__':
        pytest.main(['-s', 'test_fitt.py'])
@pytest.fixture()
def open_browser():
    print('dakai ')
    yield
    print('teardown')
    print('guanbi')

@pytest.mark.usefixtures('open_browser')#加了此句的自动应用
def test_login():
    print('login')
def test_l():
    print('case1:l')

@pytest.mark.usefixtures('open_browser')
def test_nl():
    print('case2:nl')
if __name__ == '__main__':
        pytest.main(['-s', 'test_fitt.py'])

带参数传递

  • @pytest.fixture(params=[1,2,3,‘linda’])
  • 方法参数中写request
test_user_data = [12,3,'linda']
@pytest.fixture(params=test_user_data)
def login_r(request):
    usr = request.param
    print('登录:',usr)
    return usr

def test_2(login_r):
    print(login_r)
if __name__ == '__main__':
        pytest.main(['-s', 'test_fitt.py'])

mark参数化

  • 场景:测试数据和测试预期结果一一对应
  • @pytest.mark.parametrize
@pytest.mark.parametrize('test_input,expected',[
    ('3+6',8),('1+5',6)
])
def test_eval(test_input,expected):
    assert eval(test_input)==expected
if __name__ == '__main__':
        pytest.main(['-s', 'test_fitt.py'])

mark参数化和数据驱动

@pytest.mark.parametrize(‘需要的函数’,需要的数据,indirect = True)

test_user_data = [12,3,'linda']
@pytest.fixture(scope='module')
def login_r(request):
    usr = request.param
    print('登录:',usr)
    return usr
@pytest.mark.parametrize('login_r',test_user_data,indirect=True)
def test_2(login_r):
    a = login_r
    print('login_r',a)
    assert a!=''
if __name__ == '__main__':
        pytest.main(['-s', 'test_fitt.py'])

多个参数化和数据驱动结合

  • 场景:数据读入,多个数据组合进行测试
  • 通过字典格式传入数据

单个数据输入

test_user_data = [{'username':'111','password':'777777'},
                  {'username':'222','password':'888888'},
                {'username':'123','password':''}]

@pytest.fixture(scope='module')
def login_r(request):
    usr = request.param['username']
    psw = request.param['password']
    print('登录:',usr)
    if psw:
        return True
    else:
        return False

@pytest.mark.parametrize('login_r',test_user_data,indirect=True)
def test_2(login_r):
    a = login_r
    print('login_r',a)
    assert a,'none'
if __name__ == '__main__':
        pytest.main(['-s', 'test_fitt.py'])

组合数据输入

test_user_data1 = [{'username':'111','password':'777777'},
                  {'username':'222','password':'888888'},
                {'username':'123','password':''}]
test_user_data2 = [{'q':'tb','count':2,'page':3},
                    {'q':'ali','count':2,'page':3},
                    {'q':'pdd','count':2,'page':3}
                   ]
@pytest.fixture(scope='module')
def login_r(request):
    usr = request.param['username']
    psw = request.param['password']
    print('登录:',usr)
    if psw:
        return True
    else:
        return False

@pytest.fixture(scope='module')
def query(request):
    q = request.param['q']
    count = request.param['count']
    page = request.param['page']
    print('ci:',q)
    return request.param
#从下往上执行,先执行离函数名进的
@pytest.mark.parametrize('query',test_user_data2,indirect=True)
@pytest.mark.parametrize('login_r',test_user_data1,indirect = True)
def test_2(login_r,query):
    a = login_r
    print('login_r',a)
    print(query)
    assert a,'none'
if __name__ == '__main__':
        pytest.main(['-s', 'test_fitt.py'])

mark中的skip

  • 场景:不想运行的用例、无法运行的用例、需要跳过的用例
  • @pytest.mark.skip跳过,skipif在某些条件下才希望通过
@pytest.mark.skipif(sys.platform =='win32',reason ='不在windows下运行')
def test_login():
    print('tiaoguo')

mark中的xfail

  • 场景:测试通过是预计会失败,希望由于某些情况而失败
  • @pytest.mark.xfail
@pytest.mark.xfail
def test_xfail():
    print(broken_fixture())
def broken_fixture():
    raise Exception('中断')

自定义标记mark只执行部分用例

  • 场景:多平台代码在一个文件里
  • @pytest.mark.apptest
  • 执行 -s 文件名 -m 标记
def test_q1():
    pass
@pytest.mark.webtest
def test_q2():
    pass
@pytest.mark.ios
def test_q2():
    pass
@pytest.mark.android
def test_q2():
    pass
pytest -s test_fitt.py -m webtest

通过文件名类名方法及组合调用部分用例

  • 场景:只执行符合要求的部分用例
  • 方法1:直接输入文件名
pytest -v test_a1.py::TestClass::test_one
  • 方法2:使用 -k
pytest -k "TestClass or test_one"
pytest -k "TestClass and test_one"

执行用例出错时停止

  • 遇到错误停止测试 -x
  • 用例错误个数达到指定数量n时停止测试 --maxfail =n
pytest -x -v -s test_fitt.py
pytest -x -v -s test_fitt.py --maxfail = 10

超时,失败重新执行

  • 场景:超时导致失败
  • 使用pytest-rerunfailures插件(使用pip工具下载)
  • 具体操作:在命令行输入pytest --reruns [次数] [文件名]
    在这里插入图片描述

多条断言

  • 场景:多个数据比较,防止出现一个assert不通过,后面的就都不通过的情况
  • 使用:pytest.assume (使用pip install pytest-assume 命令下载assume插件)
def test_multiple_assert():
pytest.assume(1==2)
pytest.assume(2==2)
pytest.assume(3==2)

用例依赖

  • 在web测试中,上下测试用例页面切换有依赖关系;
  • 在修改信息的页面中,依赖于前用例已经创建好的信息,如修改账号信息,依赖于已经创建好的数据
  • 使用pytest-ordering插件
  • 具体操作:@pytest.mark.run(order = 顺序)
import time
value = 0
@pytest.mark.run(order = 2)
def test_add2():
    print('2')
    time.sleep(2)
    assert value ==10
@pytest.mark.run(order = 1)
def test_add():
    print('1')
    global value
    value =10
    assert value ==10

设定好顺序后会先执行order=1的方法,再执行order=2的方法

多线程并行和分布式执行

  • 场景:多机器一起测试减少时间
  • pytest-xdist 插件
  • 前提:用例之间是独立的,没有先后顺序
  • 多cpu并行执行, pytest -n 并行数量
  • 多终端下一起执行

pytest-html生成报告

  • pytest-html
pytest -v -s --html = report.html --self-contained-html
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值