pytest基础知识
1 用例设计
文件名和函数命名规范:
- pytest会自动收集以
test_
开头或者_test
结尾的python文件作为测试文件 - 测试文件中的测试函数或方法也需要以
test_
开头 - 测试类需要以
Test
开头,且测试方法也需要以test_
开头。 - 测试类不包含
__init__
方法
2 用例执行
用例执行的方式主要有以下几种:
2.1 主函数模式
- 运行所有测试用例:
pytest.main()
- 运行执行模块的测试用例:
pytest.main(['-vs','模块名.py'])
- 运行指定目录的测试用例:
pytest.main(['-vs','./目录名'])
- 通过nodeID指定用例运行:
pytest.main(['-vs','模块名.py::类名::方法名'])
2.2 命令行模式
- 运行所有测试用例:在命令行直接输入
pytest
- 运行指定模块的测试用例:
pytest -vs 模块名.py
- 运行指定目录的测试用例:进入到对应目录,然后执行
pytest
,或者在上级目录执行pytest 目录名称/
- 运行模块模块内的某个测试方法或测试类:
pytest 模块名.py::函数名或类名
2.3 通过标记执行
使用pytest -m 标记名
来执行具有特定标记的测试用例或测试类。适用于大量测试用例中快速筛选出需要执行的用例。
2.4 参数化执行
使用参数化装饰器@pytest.mark.parametrize
来对测试用例进行参数化,从而执行具有不同输入参数的测试。
3 用例跳过
跳过测试用例主要有以下几种:
3.1 无条件跳过
- 使用装饰器
@pytest.mark.skip(reason="跳过原因")
来标记整个测试方法、类或者模块,参数可选 - 在测试方法内部,如果满足某个条件不想继续执行测试,可以使用
pytest.skip("unsupported configuration")
来跳过当前的测试
3.2 有条件跳过
- 使用装饰器
@pytest.mark.skipif(condition,reason="跳过原因")
,其中的条件是一个布尔表达式,当为True
时会跳过,原因参数可选
3.3 跳过整个模块
- 设置
pytestmark=pytest.mark.skip("跳过模块中所有测试")
来无条件跳过模块中的所有测试 - 同样,使用
pytestmark=pytest.mark.skipif(condition)
根据条件跳过整个模块
4 用例执行顺序
4.1 使用pytest_ordering
插件
- 通过
pip install pytest_ordering
命令进行安装 - 使用
@pytest.mark.run(order=x)
装饰器来控制测试用例的执行顺序。这里的x
是整数,数字越小越先执行,如果同时存在正数和负数,则正数优先级高于负数。即先正后负,先小后大。
4.2 规范测试用例命名
- pytest模块会根据测试用例的名称按照ASCII码顺序进行自动排序
5 测试用例预期失败标记
5.1 使用pytest.mark.xfail
装饰器
- 当知道某个测试用例由于某些原因会失败时,可以使用装饰器来标记为预期失败,如果确实失败,pytest会将其标记为”xfailed”,而不是普通的失败,如果用例意外通过,会将其标记为”xpass”
- 可以使用
@pytest.mark.xfail(condition,reason=None)
来根据条件判断是否标记测试用例为预期失败。当条件为True
时会被标记为预期失败
5.2 使用pytest.xfail
函数
- 在测试用例函数内部,可以使用
pytest.xfail(reason)
来标记测试用例为预期失败。调用此函数后,测试用例的后续代码将不会执行。
6 测试用例参数化
可以使用@pytest.mark.parametrize
装饰器来对测试用例进行参数化,从而运行多个具有不同输入参数的测试。该装饰器接收参数和列表,参数支持多个,解包进行赋值
1 | import pytest |
在这个例子中,我们添加了一个额外的skip_reason
参数到参数化列表中。如果skip_reason
有值,我们使用pytest.skip()
来跳过该实例。对于预期失败的实例,我们直接在测试函数内部使用pytest.xfail()
。注意,你还可以使用pytest.param()
与marks
参数来直接给特定参数化实例添加标记。
7 断言
使用assert
8 捕获异常
使用pytest.raises()
进行异常捕获
9 固件
9.1 固件的基本知识
基本概念
fixture的主要目的是提供可重用的测试资源,如配置数据、网络连接、数据库连接等。通过在测试用例中使用fixture,你可以确保这些资源在测试执行前被正确设置,并在测试执行后被清理。
作用域
function:默认的作用域,每个测试用例都会调用一次fixture。
class:每个测试类调用一次fixture,即使类中的每个方法都调用fixture,也只在第一个用例前执行一次。
module:每个.py文件调用一次fixture,针对一个文件下的所有用例只执行一次。
session:多个文件调用一次fixture,用于多个.py文件一起只调用一次的场景。这需要在目录下新建一个conftest.py文件来定义session级的fixture。
自动适配
使用@pytest.fixture(autouse=True)
进行自动适配,当所有的测试都依赖于它时,可以设置为自动适配
9.2 固件的使用
一、设置测试环境
假设你正在编写针对某个Web API的测试,每次运行测试之前,你都需要确保API服务是可用的,并且具有一些预设的数据。你可以使用fixture来设置这样的测试环境。
1 | import requests |
在这个例子中,api_session
fixture在模块级别上被定义,意味着它会在模块中的所有测试用例之前被创建一次,并在所有测试用例执行完毕后被销毁。每个测试用例通过接受api_session
作为参数来使用它,确保它们使用的是相同的API会话实例。
二、提供测试数据
另一个常见的使用场景是为测试用例提供数据。这些数据可以是静态的,也可以是根据某种条件动态生成的。
1 | import pytest |
在这个例子中,test_data
fixture返回了一个字典,该字典包含了测试用例所需的测试数据。通过将test_data
作为参数传递给test_user_data
测试用例,你可以确保测试数据在每次运行测试时都是可用的。
三、清理测试资源
在测试完成后,有时需要清理创建的资源,如数据库记录、临时文件等。fixture也可以用来执行这些清理操作。
1 | import os |
在这个例子中,temp_file
fixture使用了yield
语句来定义了一个生成器。在yield
之前的代码块中,我们创建了一个临时文件。当测试用例开始执行时,它会从yield
语句处继续执行,并且可以使用这个临时文件。当测试用例完成后,控制流会返回到fixture,并执行yield
之后的代码块,即关闭临时文件,从而完成清理工作。
四、fixture的依赖关系
有时一个fixture可能依赖于另一个fixture。例如,你可能需要一个fixture来初始化数据库连接,而另一个fixture依赖于该连接来准备特定的数据。
1 | import pytest |
在这个例子中,prepared_data
fixture依赖于db_connection
fixture。pytest会确保db_connection
fixture在执行prepared_data
fixture之前被创建和初始化。这样,你就可以在prepared_data
fixture中使用数据库连接来准备测试所需的数据。
10 运行参数
-s:输出调试信息
-v:显示更详细的信息
-n=num:启动多线程或分布式运行测试用例。需要安装pytest-xdist
插件
-k=value:用例的nodeid包含value值的测试用例被执行
-m=标签名:执行被@pytest.mark.标签名
标记的用例
-x:只要有一个用例执行失败就停止当前线程的测试执行
-maxfail=num:自定义失败次数
-returns=num:失败用例重跑num次,需要安装pytest-rerunfailures
11 其他
在方法中添加标记,通过改变方法中的pytestmark属性来实现
1 | functionName.pytestmark = pytest.mark.skip(reason="跳过") |
在pytest的item中,可以通过调用item的add_marker方法来增加标记
1 | item.add_marker(mark_name) |