• Novice学Pytest(9)参数化


    一、前言

      写用例脚本时,只有测试数据和期望结果不一样,但操作步骤是一样的测试用例,可以用参数化。pytest允许在多个级别启用测试参数化

    • pytest.fixture() 允许fixture有参数化功能
    • @pytest.mark.parameterize 允许在测试函数或类中定义多组参数和fixtures
    • pytest_generate_tests 允许定义自定义参数化方案或扩展

    二、未参数化的示例代码

    1 def test_one():
    2     assert 3 + 5 == 8
    3 
    4 def test_two():
    5     assert 2 + 4 == 6
    6 
    7 def test_three():
    8     assert 3 * 

     以上三个用例都是加法计算,然后断言和,重复写3个类似的用例有点冗余

    三、参数化的示例代码

    1 @pytest.mark.parametrize("test_input,expected",[("3+5",8),("2+4",6),("3*4",11)])
    2 def test_eval(test_input,expected):
    3     print(f"测试数据{test_input},期望结果{expected}")
    4     assert eval(test_input) == expected

      执行结果:

      we can see:只有一条用例,但是利用参数化输入三组不同的测试数据和期望结果,执行用例数也是3个,节省很多代码

    五、工作思考

      1、写登录模块的用例脚本时,根据等价类划分,我们一般会测试账号和密码正确、账号不存在、密码错误、账号为空、密码为空和账号密码都为空

      2、这些用例的区别在于输入的测试数据和对应的交互结果

      3、我们可以只写一条登录测试用例,然后把多组测试数据和期望结果参数化,节省代码量

    六、源码分析

    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"【需要用逗号分隔】

    备注:源码中写了可以是参数字符串的list或者tuple,但博主实操过是不行的,不知道是不是写的有问题,大家可以看看评论下

    示例

    @pytest.mark.parametrize(["name", "pwd"], [("yy1", "123"), ("yy2", "123")])
    @pytest.mark.parametrize(("name", "pwd"), [("yy1", "123"), ("yy2", "123")])
    @pytest.mark.parametrize("name,pwd", [("yy1", "123"), ("yy2", "123")])
    备注

    有朋友提出现在上面标注错的两个可以正常使用了

    argvalues
    源码解析:

    The list of argvalues determines how often a test is invoked with different argument values.
    If only one argname was specified argvalues is a list of values.【只有一个参数,则是值列表】
    If N argnames were specified, argvalues must be a list of N-tuples, where each tuple-element specifies a value for its respective argname.【如果有多个参数,则用元组来存每一组值】
    含义:参数值列表

    格式:必须是列表,如:[ val1,val2,val3 ]

    如果只有一个参数,里面则是值的列表如:@pytest.mark.parametrize("username", ["yy", "yy2", "yy3"])

    如果有多个参数例,则需要用元组来存放值,一个元组对应一组参数的值,如:@pytest.mark.parametrize("name,pwd", [("yy1", "123"), ("yy2", "123"), ("yy3", "123")])

    备注:虽然源码说需要list包含tuple,但我试了下,tuple包含list,list包含list也是可以的........

    ids
    含义:用例的ID

    格式:传一个字符串列表

    作用:可以标识每一个测试用例,自定义测试数据结果的显示,为了增加可读性

    强调:ids的长度需要与测试数据列表的长度一致

    indirect
    作用:如果设置成True,则把传进来的参数当函数执行,而不是一个参数

    七、装饰测试类

     1 import pytest
     2 data_1 = [(1,2,3),(4,5,9)]
     3 @pytest.mark.parametrize('a,b,expected',data_1)
     4 class TestParametrize:
     5     def test_parametrize(self,a,b,expected):
     6         print("\n测试函数11111 测试数据为\n{}{}.format(a,b")
     7         assert a + b == expected
     8 
     9     def test_parametrize_two(self,a,b,expected):
    10         print("\n测试函数22222 测试数据为\n{}-{}".format(a,b))
    11         assert a + b == expected

      执行结果: 

      Notes:当装饰器@pytest.mark.parametrize装饰测试类时,会将数据集合(比如上面的data_1)传递给类的所有测试用例方法

    八、多个参数化装饰器--举例笛卡尔积

    1 import pytest
    2 
    3 # 类似于笛卡尔积,有序组合
    4 data_one = [1,2,3]
    5 data_two = ["a","b"]
    6 @pytest.mark.parametrize("a",data_one)
    7 @pytest.mark.parametrize("b",data_two)
    8 def test_parametrize_one(a,b):
    9     print(f"\n笛卡尔积 测试数据为:{a},{b}")

      执行结果:

      Notes:

    • 一个函数或一个类可以装饰多个 @pytest.mark.parametrize
    • 这种方式,最终生成的用例数是n*m,比如上面的代码就是:参数a的数据有3个,参数b的数据有2个,所以最终的用例数有3*2=6条

    九、参数化,传入字典数据

     1 import pytest
     2 # 字典
     3 data_one = (
     4     {
     5         "user":1,
     6         "pwd":2
     7     },
     8     {
     9         "user":3,
    10         "pwd":4
    11     }
    12 )
    13 
    14 @pytest.mark.parametrize("dic",data_one)
    15 def test_parametrize_one(dic):
    16     print(f"测试数据为\n{dic}")
    17     print(f'user:{dic["user"]},pwd:{dic["pwd"]}')

      执行结果:

    十、参数化,标记数据

     1 import pytest
     2 
     3 # 标记参数化
     4 @pytest.mark.parametrize("test_input,expected",[("3+5",8),
     5                                                 ("2+4",6),
     6                                                 pytest.param("3*4",11,marks=pytest.mark.xfail),
     7                                                 pytest.param("3*5",16,marks=pytest.mark.skip)
     8                                                 ])
     9 def test_mark(test_input,expected):
    10     assert eval(test_input) == expected

      执行结果:

    十一、参数化,增加可读性

     1 import pytest
     2 
     3 # 增加可读性
     4 data_one = [(3,5,8),(2,4,6)]
     5 
     6 # ids
     7 ids = ["a:{} + b:{} = expected:{}".format(a,b,expected) for a,b,expected in data_one]
     8 @pytest.mark.parametrize("a,b,expected",data_one,ids=ids)
     9 class Testparametrize:
    10     def test_parametrize(self,a,b,expected):
    11         print("\n测试函数1 测试数据为\n{}-{}".format(a,b))
    12         assert a + b == expected

      执行结果:

      Notes:多少组数据,就要有多少个id,然后组成一个id的列表,作用主要是为了更加清晰看到用例的含义。

    参考链接:https://www.cnblogs.com/poloyy/p/12675457.html

  • 相关阅读:
    react 使用 redux 的时候 用 ref获取子组件的state
    node-rsa 非对称加密和解密
    electron 前端开发桌面应用
    react-router v4 使用 history 控制路由跳转
    react 写一个贪吃蛇
    【Java并发编程】:并发新特性—塞队列和阻塞栈
    【Java并发编程】:并发新特性—Executor框架与线程池
    【Java并发编程】:深入Java内存模型—内存操作规则总结
    【Java并发编程】:深入Java内存模型——happen-before规则及其对DCL的分析
    【Java并发编程】:加锁和volatile变量
  • 原文地址:https://www.cnblogs.com/huainanhai/p/15170167.html
Copyright © 2020-2023  润新知