读后笔记 -- Pytest框架与自动化应用 Chapter4:DDT 和 参数传递
4.2 参数化应用
1. 单一参数化 / 多参数化
# content of test_mark_parametrize.py mport pytest @pytest.mark.parametrize("test_case", [1, 2, 3, 'orange', 'apple']) def test_string(test_case): # 单一参数化 print(f"\n我们的测试数据:{test_case}") @pytest.mark.parametrize("test_input, expected", [("3 + 5", 8), ("2 + 5", 7), ("7 * 5", 30), ]) def test_eval(test_input, expected): # 多参数化 # eval将字符串str当成有效的表达式来求值并返回计算结果 assert eval(test_input) == expected
2. 多个参数化
# content of test_multi.py """多个参数化,将会变成组合的形式,示例将产生 3*2 = 6 个组合""" import pytest @pytest.mark.parametrize('test_input', [1, 2, 3]) @pytest.mark.parametrize('test_output, expected', [(1, 2), (3, 4)]) def test_multi(test_input, test_output, expected): pass
3. pytestmark 实现参数化
# content of test_module.py import pytest # 通过对 pytestmark 赋值,参数化一个测试模块 pytestmark = pytest.mark.parametrize('test_input, expected', [(1, 2), (3, 4)]) def test_module(test_input, expected): assert test_input + 1 == expected
4.4 argnames 参数
1. argnames 与测试方法中的参数关系
# 1) 测试方法未声明, mark.parametrize 中声明 # if run this only, report "function uses no argument 'expected' @pytest.mark.parametrize('input, expected', [(1, 2)]) def test_sample1(input): assert input + 1 == 1
# 2) 测试方法参数声明的范围小于 mark.parametrize 中声明的范围:parametrize 定义了 expected,又在方法入参中赋值 expected,将出错 # if run this only, report "function already takes an argument 'expected' with a default value" @pytest.mark.parametrize('input, expected', [(1, 2)]) def test_sample2(input, expected = 2): assert input + 1 == 1
# content of test_mark_param_sub.py import pytest @pytest.fixture def expected3(): return 2 # 3) test_sample3 没有定义 expected,test_sample3 的参数 expected3 可以从 fixture 中获取 @pytest.mark.parametrize('input3', [(1)]) def test_sample3(input3, expected3): assert input3 + 1 == expected3 @pytest.fixture def expected4(): return 2 # 4)parametrize() 的参数化值覆盖了 fixture 的值 @pytest.mark.parametrize('input4, expected4', [(1, 2), [2, 3], set([3, 4])]) def test_sample4(input4, expected4): assert input4 + 1 == expected4
4.5 argvalues 参数
1. 使用 pytest.param 为 argvalues 赋值
# content of test_mark_param_sub.py import pytest @pytest.mark.parametrize( ('n', 'expected5'), [(4, 2), # 正常传参 为 argvalues 赋值 pytest.param(6, 3, marks=pytest.mark.xfail, id='XPASS')] # 使用 pytest.parm() 为 argvalues 赋值 ) def test_param5(n, expected5): assert n / 2 == expected5
4.6 indirect 参数
# test_mark_param_indirect.py """ 应用场景:同一个变量 在 fixture 定义和 参数化里定义 当 indirect = False, var1 使用的是 参数化里面传的变量值 当 indirect = True, var1 使用的是 fixture 的变量值 """ import pytest @pytest.fixture def max_f(request): return request.param - 1 @pytest.fixture def min_f(request): return request.param + 1 # 默认 indirect 为 False,min_f 和 max_f 使用的是后面的数据。 @pytest.mark.parametrize('min_f, max_f', [(1, 2), (3, 4)]) def test_indirect_default(min_f, max_f): assert min_f < max_f # indirect 为 True时,min_f 和 max_f 对应的实参重定向到同名的 fixture 的数据 @pytest.mark.parametrize('min_f, max_f', [(1, 2), (3, 4)], indirect=True) def test_indirect_true(min_f, max_f): assert min_f > max_f # indirect = ['max_f'],仅 max_f 重定向到 fixture 的数据 @pytest.mark.parametrize('min_f, max_f', [(1, 2), (3, 4)], indirect=['max_f']) def test_part_indirect(min_f, max_f): assert min_f == max_f
4.7 ids 参数
# content of test_mark_param_ids.py import pytest @pytest.mark.parametrize('input_1, expected', [(1, 2), (3, 4)], ids=['first', 'second']) def test_ids_with_ids1(input_1, expected): """ids 的长度 = argvalues 的长度""" pass @pytest.mark.parametrize('input_2, expected', [(1, 2), (3, 4)], ids=['num', 'num']) def test_ids_with_ids2(input_2, expected): """ids 相同时,则显示 idxxx (索引),该示例显示 num0, num1""" pass @pytest.mark.parametrize('input_3, expected', [(1, 2), (3, 4)], ids=['num', '中文']) def test_ids_with_ids4(input_3, expected): """在 pytest.ini 定义一个变量覆盖原始配置,将解决 ids 中文显示的问题""" pass def idfn(val): return val + 1 @pytest.mark.parametrize('input_4, expected', [(1, 2), (3, 4)], ids=idfn) def test_ids_with_ids4(input_4, expected): """通过 idfn 将参数处理里一次 默认显示: (1-2) (3-4) 现在显示: (2-3) (4-5) """ pass @pytest.mark.parametrize('input_5, expected', [(1, 2), pytest.param(3, 4, id='id_via_pytest_param')], ids=['first', 'second']) def test_ids_with_ids5(input_5, expected): """pytest.param 指定的 id 将会覆盖 ids 对应的测试id 结果将显示 [first] / [id_via_pytest_param] """ pass
2. id 并可通过 "-k" 过滤
# content of test_id.py import pytest @pytest.mark.parametrize('input_1, expected', [ pytest.param(1, 2, id='Windows'), pytest.param(3, 4, id='Windows'), pytest.param(5, 6, id='Non-Windows') ]) def test_ids_with_id(input_1, expected): pass if __name__ == '__main__': """ 1. 使用下面的方式,不能过滤。 2. 有效的方式:通过 terminal 执行 "pytest -k 'Non-Windows' .\test_ids.py" """ pytest.main(['-k', 'Non-Windows', 'test-ids.py'])
4.8 scope 参数
# content of test_scope.py import pytest @pytest.fixture(scope='module') def test_input(request): pass @pytest.fixture(scope='module') def expected(request): pass @pytest.mark.parametrize('test_input, expected', [(1, 2), (3, 4)], indirect=True) def test_scope1(test_input, expected): pass @pytest.mark.parametrize('test_input, expected', [(1, 2), (3, 4)], indirect=True) def test_scope2(test_input, expected): pass @pytest.mark.parametrize('test_input, expected', [(1, 2), (3, 4)], scope="module") def test_scope3(test_input, expected): pass @pytest.mark.parametrize('test_input, expected', [(1, 2), (3, 4)], scope="module") def test_scope4(test_input, expected): pass @pytest.mark.parametrize('test_input, expected', [(1, 2), (3, 4)]) def test_scope5(test_input, expected): pass @pytest.mark.parametrize('test_input, expected', [(1, 2), (3, 4)]) def test_scope6(test_input, expected): pass
通过下面的输出,可以看出:
- 1. 将先执行所有标识 scope= module第一组数据,再执行所有标识 scope= module第二组数据
- 2. 未标识 scope=module 的,继续按原方式执行,一个方法组合执行完执行另一个方法的组合
4.9 pytest_generate_tests hook方法
1
2
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)