文章目录
- [一. Pytest 参数化用例(用例传参优化)](#一. Pytest 参数化用例(用例传参优化))
-
- [1. 参数化简介](#1. 参数化简介)
- [2. 参数化使用方法 - @pytest.mark.parametrize()](#2. 参数化使用方法 - @pytest.mark.parametrize())
- [二. Pytest 标记测试用例(自定义执行那些用例)](#二. Pytest 标记测试用例(自定义执行那些用例))
-
- [1. 标记测试用例的实现方式](#1. 标记测试用例的实现方式)
- [2. 解决自定义标签名抛出的异常](#2. 解决自定义标签名抛出的异常)
- [三. Pytest 设置跳过、预期失败用例(设置直接跳过和根据条件跳过某些用例)](#三. Pytest 设置跳过、预期失败用例(设置直接跳过和根据条件跳过某些用例))
-
- [1. 使用场景](#1. 使用场景)
- [2. 跳过用例](#2. 跳过用例)
- [四. Pytest 运行用例](#四. Pytest 运行用例)
- [五. Pytest 测试用例调度与运行](#五. Pytest 测试用例调度与运行)
- [六. Pytest 命令行常用参数](#六. Pytest 命令行常用参数)
- [七. Python 执行 Pytest](#七. Python 执行 Pytest)
- [八. Pytest 异常处理](#八. Pytest 异常处理)
一. Pytest 参数化用例(用例传参优化)
1. 参数化简介
Pytest 参数化,即将测试用例的参数以动态传参的形式进行传递和获取,以此实现数据和脚本之间的解耦分离
举个例子:验证登录,如果账号密码用固定参数去查询,那么每次都需要去更改参数中的账号密码信息,或者去copy一份用例代码重新修改参数值,这显然极大的增加了工作量也很不美观,这个时候就可以用参数化来实现,每次只需要传递单独的参数,无需去修改用例代码,省时省力。
-
参数化的优点
🔹 简化测试代码: 使用参数化测试,在测试代码中可以使用单个测试函数来覆盖多种不同的测试情况。这样可以避免编写大量重复的测试代码,并提高代码的可读性和维护性。
🔹 减少维护成本: 如果需要对测试逻辑进行更改或添加更多测试用例,只需修改一个参数化测试案例,就可以覆盖所有相关的测试情况,减少了维护的工作量和成本。
2. 参数化使用方法 - @pytest.mark.parametrize()
使用 @pytest.mark.parametrize()装饰器为测试函数提供参数化数据。因为参数化的性质,被广泛的应用在测试用例中
-
@pytest.mark.parametrize()的使用示例
py@pytest.mark.parametrize( "参数名", [变量], ids=[用例名] ) def test_demo(变量名): result = 变量名 assert result == "..." -
@pytest.mark.parametrize()的参数化传参类型
🔹 单参数
🔹 多参数
🔹 笛卡尔积(多个集合中,每个元素"两两(或多两)组合"的所有可能情况)
参数化-单参数传参
用例只需要检查一个参数的值即可,可以将数据放到列表或者元组中,在将其作为参数传递
-
代码实现
pyimport pytest search_list = ['张三', '李四', '王五', '赵六'] @pytest.mark.parametrize('name', search_list) def test_search(name): assert name in search_list- 运行结果

- 运行结果
参数化-多参数传参
用例需要多个参数时,可以将数据放在列表嵌套元组或者列表中,在将其作为参数传递
-
代码实现:数据放在元组中
pyimport pytest @pytest.mark.parametrize( "username,password", [ ("root", 123456), ("admin", "admin"), ("7682134", 485238) ] ) def test_mark_more(username, password): print(f"username:{username},密码:{password}") -
代码实现:数据放在列表中
pyimport pytest @pytest.mark.parametrize( "username,password", [ ["root", 123456], ["admin", "admin"], ["7682134", 485238] ] ) def test_mark_more(username, password): print(f"username:{username},密码:{password}")- 运行结果

- 运行结果
参数化-用例重命名(ids参数)
从上述学习中可知,参数化是录入了几条参数数据,用例就会被执行了几次,而这些用例的命名规则就是参数值的内容,多参数以"-"进行拼接。这样的用例名是不美观的,这时可以用ids参数来给用例重命名
-
代码实现
pyimport pytest @pytest.mark.parametrize( "username,password", [ ["root", 123456], ["admin", "admin"], ["7682134", 485238] ], ids=['user1', 'user2', 'user3'] ) def test_mark_more(username, password): print(f"username:{username},密码:{password}")- 运行结果:通过结果可以看出,用例名称被根据ids参数的顺序修改了

- 运行结果:通过结果可以看出,用例名称被根据ids参数的顺序修改了
注意:当别名为中文时,会显示为 unicode 编码,需要自定义插件解决。
笛卡尔积
笛卡尔积:多个集合中,每个元素"两两(或多两)组合"的所有可能情况
-
举个例子:
-
现在有如下两组衣服颜色,请列举出所有搭配
-
上衣:{红色, 蓝色}
-
裤子:{牛仔裤, 运动裤}
-
-
搭配结果
- 红色 + 牛仔裤
- 红色 + 运动裤
- 蓝色 + 牛仔裤
- 蓝色 + 运动裤
-
-
代码实现
pyimport pytest @pytest.mark.parametrize( "b", ["红色", "蓝色"] ) @pytest.mark.parametrize( "a", ["牛仔裤", "运动裤"] ) def test_param1(a, b): print(f"笛卡积形式的参数化中 a={a} , b={b}")- 运行结果

- 运行结果
二. Pytest 标记测试用例(自定义执行那些用例)
目前学习pytest框架已知,符合命名规范的py文件以及类和函数均会被pytest框架扫描并执行。当测试用例随着规模逐渐扩大,全部用例均执行这显然是不符合常理的,所以这个时候就需要使用 pytest 框架的装饰器来标记测试用例,以此来实现 "需要执行那些用例就执行那些用例的效果"
-
标记测试用例的优点🔹 组织和分类测试: 标记测试用例可以将标记名自定义配置,比如根据分组归类,便于组织和管理测试。例如,可以为功能测试、性能测试、回归测试等不同类型的测试案例创建不同的标记名称,使测试套件更加可读和易于维护。
🔹 灵活选择测试: 通过标记测试用例,可以在运行测试时选择性地执行或跳过特定的测试用例。这对于执行特定类型或特定条件下的测试非常有用,提高了测试效率。
1. 标记测试用例的实现方式
-
使用步骤如下
🔹 1、在测试用例方法上加 @pytest.mark.标签名。
🔹 2、命令行执行用例时使用 -m 标签名 来指定要执行的测试用例。
-
代码实现
pyimport pytest def double(a): return a * 2 @pytest.mark.P0 def test_case_01(): assert 2 == double(1) @pytest.mark.P1 def test_case_02(): assert -2 == double(-1) @pytest.mark.P0 def test_case_03(): assert 0.2 == double(0.1) @pytest.mark.P1 def test_case_04(): assert -0.2 == double(-0.1) @pytest.mark.P2 def test_case_05(): assert 0 == double(0)-
在控制台输入命令:pytest 脚本全路径 -m "P0"
- 运行结果:从结果可以看出,结果是正确的,一共5条用例,标记为P0的只有两条,所以执行了两条,未执行三条

- 运行结果:从结果可以看出,结果是正确的,一共5条用例,标记为P0的只有两条,所以执行了两条,未执行三条
-
2. 解决自定义标签名抛出的异常
实现标记测试用例后,通过执行结果可以看到,每条 case 都抛出 PytestUnknownMarkWarning 这个异常,但此异常不影响脚本的正常执行,结果正常在输出。报出此异常的原因是你使用了自定义的标签,但是你并没有在 pytest 框架中进行任何有关这些标签的声明注册,只需要注册上就不会在抛出这些异常了。
一句话总结:pytest 不认识你写的这个 mark(标签),它怀疑你是不是拼写写错了
-
解决此异常方式
-
1、在项目根目录创建 pytest.ini 文件
- 注意文件名必须叫 pytest.ini ,并且需要在 项目根目录
-
2、在文件中注册声明标签
py[pytest] markers = P0: 主要执行 P1: 备选执行 P2: 暂不执行- 添加完声明后,在运行,可以看到异常消失了

- 添加完声明后,在运行,可以看到异常消失了
-
三. Pytest 设置跳过、预期失败用例(设置直接跳过和根据条件跳过某些用例)
在使用 pytest 进行测试开发时,有时候可能需要跳过某些测试用例或者标记某些测试用例为预期失败。pytest 提供了一些装饰器和命令行选项来实现这些功能。
1. 使用场景
🔹 1、当某些用例无法顺利通过或者尚未完成实现时,可以将其标记为跳过或预期失败,这样在整个测试运行过程中,这些用例将不会执行。
🔹 2、预期失败的测试用例会被执行,但不会导致整个测试运行失败。
2. 跳过用例
🔹 @pytest.mark.skip: 被标记的用例会直接跳过不执行
🔹 @pytest.mark.skipif: 遇到特定情况跳过该测试用例。
🔹 pytest.skip(): 在用例中添加此函数,可以直接跳过,后续流程不执行
🔹 @pytest.mark.xfail: 在用例中添加此函数,可以直接跳过,后续流程不执行
设置直接跳过某个用例不执行
-
装饰器实现:@pytest.mark.skip
-
代码实现
pyimport pytest @pytest.mark.skip def test_a(): assert True @pytest.mark.skip(reason="代码没有实现") def test_b(): assert False- 运行结果:可以看到两个用例被跳过了,均未执行

- 运行结果:可以看到两个用例被跳过了,均未执行
-
-
函数实现:pytest.skip()
-
代码实现
pydef test_skip_example(): print("方法中设置跳过用例") pytest.skip("跳过这个用例") print("是否执行?") # 这个断言不会被执行,因为测试会被跳过 assert 1 == 1- 运行结果:从结果可以看出,执行到 pytest.skip("跳过这个用例")时,后续代码未执行了

- 运行结果:从结果可以看出,执行到 pytest.skip("跳过这个用例")时,后续代码未执行了
-
设置根据条件跳过某个用例不执行
-
遇到特定情况跳过该测试用例
- 装饰器实现:@pytest.mark.skipif(条件表达式, reason="跳过原因")
-
代码实现
pyimport pytest @pytest.mark.skipif(1 == 2, reason="1是否等于2?") def test_case1(): assert True @pytest.mark.skipif(2 == 2, reason="2是否等于2?") def test_case2(): assert True- 运行结果:从结果可以看出,条件表达式失败的用例未执行

- 运行结果:从结果可以看出,条件表达式失败的用例未执行
-
- 装饰器实现:@pytest.mark.skipif(条件表达式, reason="跳过原因")
标记用例预期失败(只有失败额用例执行,跳过成功的用例)
- 与 skip 类似,当用例预期结果为 fail 时,可以直接标记用例预期失败。
- 用法:添加装饰器 @pytest.mark.xfail
注意: xfail 标记测试用例,是指该测试用例是预期失败的。这意味着测试用例可以运行,但失败时不会被视为实际失败,而是被记录为已预期的失败。
- 装饰器实现:@pytest.mark.xfail
-
代码实现
pyimport pytest @pytest.mark.xfail def test_a(): assert 1 == 2 @pytest.mark.xfail def test_b(): assert 2 == 2- 运行结果:从结果可以看出,断言结果是失败的执行了,成功的被忽略了

- 运行结果:从结果可以看出,断言结果是失败的执行了,成功的被忽略了
-