当前位置:   article > 正文

参数化@pytest.mark.parametrize【pytest系列 8】_pytest 反参数化执行测试类

pytest 反参数化执行测试类

1、pytest可以在多个地方定义参数化

  • pytest.fixture fixture可以定义参数化
  • pytest.mark.parametrize 可以让测试函数和类定义多组参数和fixture
  • pytest_generate_tests 可以定义自定义参数化方案或扩展

2、参数化场景

测试数据和期望结果不一样,但是操作步骤都一样的测试用例可以使用参数化。举个例子:

  • 未参数化代码
    def test_01():
        assert 3 + 5 == 9
    
    
    def test_02():
        assert 2 + 4 == 6
    
    
    def test_03():
        assert 2 + 9 == 42
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
  • 利用参数化优化后的代码,执行效果同上
    @pytest.mark.parametrize("input, expected"), [["3+5", 9], ["2+4", 6], ["2+9", 42]])
    def test_04(input, expected):
        assert eval(input) == expected
    
    • 1
    • 2
    • 3

实际Web UI自动化的开发场景,比如一个登录框

  1. 你肯定需要测试多种情况:账号空密码空账号密码都为空账号不存在密码错误密码正确
  2. 以上多种情况的区别在于 输入的测试数据对应的交互结果 不一样
  3. 这种情况下,我们就可以只写一条登录测试用例,把多组测试数据和期望结果参数化

2、源码分析

def parametrize(self, argnames, argvalues, indirect=False, ids=None, scope=None):

argnames

  • 源码解析: a comma-separated string denoting one or more argument names, or a list/tuple of argument strings.【被逗号分隔的字符串,表示一个或多个变量的名称,或者参数字符串的元组/列表】
  • 含义: 表示参数的名称
  • 格式:
    • 字符串 "arg1, arg2, arg3"
    • 列表 ["arg1", "arg2", "arg3"]
    • 元组 ("arg1", "arg2", "arg3")
  • 代码示例:
    @pytest.mark.parametrize("name, passwd", [["ZhangSan", "zs123"], ["LiSi", "ls123"], ["WangEr", "we123"]])
    @pytest.mark.parametrize(["name", "passwd"], [["ZhangSan", "zs123"], ["LiSi", "ls123"], ["WangEr", "we123"]])
    @pytest.mark.parametrize(("name", "passwd"), [["ZhangSan", "zs123"], ["LiSi", "ls123"], ["WangEr", "we123"]])
    
    • 1
    • 2
    • 3

argvalues

  • 源码解析:
    • The list of argvalues determines how often a test is invoked with different argument values.【argvalues列表确定使用不同参数值被测试用例调用的频率】
    • If only one argname was specified argvalues is a list of values.【如果只声明了一个参数,那么argvalues是一个列表】
    • If N argnames were specified, argvalues must be a list of N-tuples, where each tuple-element specifies a value for its respective argname.【如果声明了N个参数,那么argvalues必须是一个存放元组的列表,元组中有N个值,每个值对应每个argname】
  • 含义: 参数值列表
  • 格式: 必须是一个列表,列表中的每个值代表一组测试数据
    • 如果只有一个参数,直接使用列表存放参数值即可,可以这么表示:@pytest.mark.parametrize("username", ["test01", "test02", "test03"])
    • 如果有需要传入多个参数,则需要用元组来存放参数的值,一个元组代表一组参数的值,然后用列表来存放这些元组,可以这么表示:@pytest.mark.paramatrize("username, passwd", [("ZhangSan", "zs123"), ("LiSi", "ls123"), ("WangEr", "we123")])

ids

  • 含义: 用例的ID
  • 格式: 传一个字符串列表,长度需要与测试数据列表的长度一致
  • 作用: 可以用来标识每一个测试用例,自定义每条测试数据执行结果的显示内容

indirect

  • 作用: 如果设置成True,则会把传进来的参数当函数执行;否则就会当成参数处理。

3、常用场景

场景一:装饰测试类

  • 代码:
    data = [
        (4, 5, 9),
        (1, 2, 3),
        (2, 4, 6)
    ]
    
    
    @pytest.mark.parametrize("a, b, expect", data)
    class TestParamatrize:
        def test_paramatrize_01(self, a, b, expect):
            print(f"测试函数为: 01, 测试数据为: {a}+{b}, 期望值为: {expect}")
            assert a + b == expect
    
        def test_parametrize_02(self, a, b, expect):
            print(f"测试函数为: 02, 测试数据为: {a}+{b}, 期望值为: {expect}")
            assert a + b == expect
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
  • 结果:
    ============================= test session starts ==============================
    collecting ... collected 6 items
    
    test_01.py::TestParamatrize::test_paramatrize_01[4-5-9] PASSED           [ 16%]
    测试函数为: 01, 测试数据为: 4+5, 期望值为: 9
    
    test_01.py::TestParamatrize::test_paramatrize_01[1-2-3] PASSED           [ 33%]
    测试函数为: 01, 测试数据为: 1+2, 期望值为: 3
    
    test_01.py::TestParamatrize::test_paramatrize_01[2-4-6] PASSED           [ 50%]
    测试函数为: 01, 测试数据为: 2+4, 期望值为: 6
    
    test_01.py::TestParamatrize::test_parametrize_02[4-5-9] PASSED           [ 66%]
    测试函数为: 02, 测试数据为: 4+5, 期望值为: 9
    
    test_01.py::TestParamatrize::test_parametrize_02[1-2-3] PASSED           [ 83%]
    测试函数为: 02, 测试数据为: 1+2, 期望值为: 3
    
    test_01.py::TestParamatrize::test_parametrize_02[2-4-6] PASSED           [100%]
    测试函数为: 02, 测试数据为: 2+4, 期望值为: 6
    
    ============================== 6 passed in 0.08s ===============================
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

场景二:多个参数化装饰器,“笛卡尔积”

  • 代码:
    data_1 = [1, 2, 3]
    data_2 = ['a', 'b']
    
    @pytest.mark.parametrize("a", data_1)
    @pytest.mark.parametrize("b", data_2)
    def test_parametrize_01(a, b):
        print(f"笛卡尔积,测试数据为: {a}-{b}")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
  • 结果:会产生3 x 2 = 6组结果
    collecting ... collected 6 items
    
    test_01.py::test_parametrize_01[a-1] PASSED                              [ 16%]
    笛卡尔积,测试数据为: 1-a
    
    test_01.py::test_parametrize_01[a-2] PASSED                              [ 33%]
    笛卡尔积,测试数据为: 2-a
    
    test_01.py::test_parametrize_01[a-3] PASSED                              [ 50%]
    笛卡尔积,测试数据为: 3-a
    
    test_01.py::test_parametrize_01[b-1] PASSED                              [ 66%]
    笛卡尔积,测试数据为: 1-b
    
    test_01.py::test_parametrize_01[b-2] PASSED                              [ 83%]
    笛卡尔积,测试数据为: 2-b
    
    test_01.py::test_parametrize_01[b-3] PASSED                              [100%]
    笛卡尔积,测试数据为: 3-b
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

场景三:使用@pytest.param(values, marks, id)标记数据

  • 代码:
    @pytest.mark.parametrize("test_input, expected", [
        ("3+5", 8),
        ("2+4", 6),
        pytest.param("6*9", 42, marks=pytest.mark.xfail),
        pytest.param("6*6", 42, marks=pytest.mark.skip)
    ])
    def test_parametrize_02(test_input, expected):
        assert eval(test_input) == expected
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
  • 结果:
    =========================================================================== test session starts ============================================================================
    collected 4 items                                                                                                                                                          
    
    test_01.py::test_parametrize_02[3+5-8] PASSED                                                                                                                        [ 25%]
    test_01.py::test_parametrize_02[2+4-6] PASSED                                                                                                                        [ 50%]
    test_01.py::test_parametrize_02[6*9-42] XFAIL                                                                                                                        [ 75%]
    test_01.py::test_parametrize_02[6*6-42] SKIPPED (unconditional skip)                                                                                                 [100%]
    
    ================================================================= 2 passed, 1 skipped, 1 xfailed in 0.08s ==================================================================
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

场景四:参数化ids,增加可读性

  • 代码:
    data_3 = [
        (1, 2, 3),
        (4, 5, 9)
    ]
    
    ids = [f"a: {a} + b: {b} = expect: {expect}" for a, b, expect in data_3]
    
    
    @pytest.mark.parametrize("a, b, expect", data_3, ids=ids)
    def test_parametrize_03(a, b, expect):
        assert a + b == expect
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
  • 结果:
    ============================= test session starts ==============================
    collecting ... collected 2 items
    
    test_01.py::test_parametrize_03[a: 1 + b: 2 = expect: 3] PASSED          [ 50%]
    test_01.py::test_parametrize_03[a: 4 + b: 5 = expect: 9] PASSED          [100%]
    
    ============================== 2 passed in 0.04s ===============================
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

参考文章:https://www.cnblogs.com/poloyy/p/12675457.html

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Monodyee/article/detail/143712
推荐阅读
相关标签
  

闽ICP备14008679号