Pytest
-
# 安装pytest: pip install pytest # 升级pytest pip install -U pytest # 查看pytest版本 pytest --version # 查看已安装包列表 pip list # 查看pytest帮助文档 pytest -h # 安装第三方插件 pip install pytest-sugar pip install pytest-rerunfailures pip install pytest-xdist pip install pytest-assume pip install pytest-html
-
@pytest.mark.skipif
“@pytest.mark.skipif” 通常是在 Python 的 pytest 测试框架中使用的一个装饰器。 “skipif” 表示根据指定的条件来决定是否跳过(不执行)被装饰的测试函数。
-
pytest.raise
在
pytest
中,pytest.raises()
是一个用于测试代码是否引发特定异常的上下文管理器。import pytest def test_function_that_raises_exception(): with pytest.raises(TypeError): # 这里的代码预期会引发 TypeError 异常 some_function_that_should_raise_type_error()
在上述代码中,当执行
some_function_that_should_raise_type_error()
时,如果它引发了TypeError
异常,那么这个测试用例将通过;如果没有引发这个异常或者引发了其他异常,测试用例将失败。 -
pytest测试用例的识别与运行
-
发现用例的规则
a) 文件test_.py开头和_test.py结尾
b) Test开头的类中test开头的方法(测试类不能带有__init__方法)
c) 模块中test开头的函数(可以不在class中)
d)包中存在init方法
-
注意点:
pytest是以方法为单位发现用例的,写不写测试类根本不重要
在哪个目录下执行pytest就在哪个目录下按照上述规则去查找 -
自定义查找规则:pytest.ini
在pytest.ini中写入addopts = -p no:warnings
忽视所有的警告
-
-
参数:
- pytest / py.test
- 打印详细运行日志信息:pytest -v (最高级别信息-verbose)
- s是带控制台输出结果,也是输出详细,可以打印测试用例中print的输出:pytest -v -s 文件名
- 执行单独一个pytest模块:pytest 文件名.py
- 运行某个模块里面某个类:pytest 文件名.py::类名
- 运行某个模块里面某个类里面的方法:pytest 文件名.py::类名::方法名
- 跳过某个用例:pytest -k "类名 and not 方法名",如pytest -k "TestDemo and not test_one"
- 运行带有某标记的测试用例(pytest.mark.标记名):pytest -m 标记名
- 一旦运行到报错就停止运行:pytest -x 文件名
- 当错误达到num的时候就停止运行:pytest --maxfail=[num]
-
失败重新运行
场景:测试失败后要重新运行n次,要在重新运行之间添加延迟时间,间隔n秒再运行。安装:pip install pytest-rerunfailures
执行:
- 测试失败后重新运行3次:pytest --reruns 3 -v -s test_class.py
- 测试失败后重新运行5次且每次重新运行间隔1秒:pytest -v --reruns 5 --reruns-delay 1
- 或加入装饰器@pytest.mark.flaky(reruns = 1)
- 或可以加入pytest.ini中(addopts = -p no:warnings -s -v --reruns 2 --reruns-delay 2)
- 尝试加入main中不好用
-
多次断言,不中断
一个方法中写多条断言,通常第一条断言失败,下面的断言也不执行了。但是我们希望即使第一条断言失败,后续断言还是继续执行。
pip install pytest-assume
def test_assume(self): pytest.assume(1==2) pytest.assume(1<3) pytest.assume(1==1)
-
pytest.ini
是 pytest 测试框架的配置文件,用于定义 pytest 的运行配置。
它通常位于项目的根目录或指定的测试目录中,并且可以包含各种配置选项,以适应不同项目和测试环境的需求。
以下是一些常见的配置选项:
-
conftest
conftest.py 是 pytest 特有的测试配置文件,可以理解成一个专门放 fixture(设备、工具)的地方。一个工程下可以建多个 conftest.py 文件,通常在工程根目录下设置一个 conftest 文件,这样会起到一个全局的作用;也可以在不同的子目录下放 conftest.py ,这样作用范围只能在该层级的子目录下生效。
fixture 是在测试函数运行前后,由 pytest 执行的外壳函数,类似 unittest 中的 setup/teardown
conftest.py配置fixture注意事项
- pytest会默认读取conftest.py里面的所有fixture
- conftest.py 文件名称是固定的,不能改动
- conftest.py只对同一个package下的所有测试用例生效
- 不同目录可以有自己的conftest.py,一个项目中可以有多个conftest.py
- 测试用例文件中不需要手动import conftest.py,pytest会自动查找
- 所有同目录测试文件运行前都会执行conftest.py文件;
-
pytest.mark.parametrize
pytest.mark.parametrize
是 pytest 框架中的一个装饰器,用于在测试用例中参数化。它允许你为一个测试函数提供多个不同的参数组合,并在执行测试时自动遍历这些组合。我们可以通过ids对参数用例进行描述,如果不设置ids,就默认参数值表示.
@pytest.mark.parametrize('in_data', eval(re_data), ids=[i['detail'] for i in TestData]) def test_login(self, in_data, case_skip): """ :param : :return: """ res = RequestControl(in_data).http_request() TearDownHandler(res).teardown_handle()
-
pytest中的fixture
-
fixture
可以通过函数实现,并使用装饰器@pytest.fixture
进行装饰。fixture
的作用范围可以是测试函数、测试类、测试模块或整个测试会话。在fixture
函数中,可以编写前置准备工作代码和后置清理工作代码,并使用yeild
关键字来区分前后置代码。可以将配置提取到conftest配置类中
后置处理器用yield作为分割。
@pytest.fixture() def login(): print("登录。。。。。。。。") yield#yield作为分界线,下面是后置处理器 print("退出登录") # 将方法名带入到需要前置的方法的参数里。 def test_01(login): str = "huahua" assert "u" in str def test_02(): str = "yy" assert "y" in str def test_03(login): str = "yy0" assert "y" in str if __name__ == '__main__': pytest.main(['-vs'])
-
在conftest使用autouse参数所有的test_*自动执行fixture,无需将fixture写入到方法参数中
@pytest.fixture(scope="session", autouse=True) def work_login_init(): """ 获取登录的cookie :return: """ url = "https://www.wanandroid.com/user/login" data = { "username": 18800000001, "password": 123456 } headers = {'Content-Type': 'application/x-www-form-urlencoded'} # 请求登录接口 res = requests.post(url=url, data=data, verify=True, headers=headers) response_cookie = res.cookies cookies = '' for k, v in response_cookie.items(): _cookie = k + "=" + v + ";" # 拿到登录的cookie内容,cookie拿到的是字典类型,转换成对应的格式 cookies += _cookie # 将登录接口中的cookie写入缓存中,其中login_cookie是缓存名称 CacheHandler.update_cache(cache_name='login_cookie', value=cookies)
-
四种作用域
- function:每一个函数或方法都会调用
- class:每一个类调用一次,一个类中可以有多个方法
- module:每一个.py文件调用一次,该文件内又有多个function和class
- session:多个文件调用一次,可以跨.py文件调用(通常这个级别会结合conftest.py文件使用)
-
-
pytest的执行流程
pytest启动后,会先加载.ini文件读取ini文件中设置的对应参数,并给框架内部的变量赋值
加载完.ini文件,会去加载内部的conftest.py文件
最后执行测试用例
-
如何做冒烟测试?
在pytest.ini中定义好markers的类别
markers = smoke: 冒烟测试 regression: 回归测试
使用装饰器@pytest.mark.smoke定义该测试用例类别
在pytest.ini中执行 -m smoke
addopts = -p no:warnings -m smoke
-
如何统计测试结果
统计测试结果的目的是存放在内存中,随时使用,可以进行发送邮件等操作
pytest_terminal_summary
是一个Pytest
钩子函数,它在测试执行完成后被调用只需在conftest.py中写个 pytest_terminal_summary 函数收集测试结果
钩子函数是一种在程序执行过程中的特定点被调用的函数。它们允许开发者在程序的特定阶段插入自己的代码,以执行自定义的操作或修改程序的行为。
钩子函数的实现通常由框架或系统提供,开发者只需注册或实现相应的钩子函数,系统在特定的时间点或事件发生时会自动调用这些函数
def pytest_terminal_summary(terminalreporter, exitstatus, config): '''收集测试结果''' print(terminalreporter.stats) print("total:", terminalreporter._numcollected) print('passed:', len(terminalreporter.stats.get('passed', []))) print('failed:', len(terminalreporter.stats.get('failed', []))) print('error:', len(terminalreporter.stats.get('error', []))) print('skipped:', len(terminalreporter.stats.get('skipped', []))) # terminalreporter._sessionstarttime 会话开始时间 duration = time.time() - terminalreporter._sessionstarttime print('total times:', duration, 'seconds')