pytest实现用例参数化(@pytest.mark.parametrize)

网友投稿 428 2022-08-28


pytest实现用例参数化(@pytest.mark.parametrize)

一、pytest实现测试用例参数化(@pytest.mark.parametrize)

@pytest.mark. parametrize装饰器可以实现对测试用例的参数化,方便测试数据的获取。

@pytest.mark. parametrize的基本使用:

方便测试函数对测试数据的获取。 方法: parametrize(argnames, argvalues, indirect=False, ids=None, scope=None)

参数说明:

参数化用法

1、单个参数【测试方法入参只有一个参数】

# file_name: test_parametrize.pyimport pytestclass Test_D: @pytest.mark.parametrize("a", [1, 2, 3]) # 参数a被赋予3个值,test_a将会运行3遍 def test_a(self, a): # 参数必须和parametrize里面的参数一致 print('\n------------------> test_a has ran, and a = {}'.format(a)) assert 1 == aif __name__ == '__main__': pytest.main(['-s', 'test_parametrize.py'])

运行结果:

从运行结果中可以看到test_a方法被执行了3遍,说明参数a参数化成功。

2、多个参数【测试方法入参有多个参数】

# file_name:test_parametrize.pyimport pytestclass Test_D: @pytest.mark.parametrize("a,b", [(1, 2), (2, 3), (3, 4)]) # 参数a,b均被赋予三个值,函数会运行三遍 def test_b(self, a, b): # 参数必须和parametrize里面的参数一致 print('\n------------------> test_b has ran, and a = {}, b = {}'.format(a, b)) assert 1if __name__ == '__main__': pytest.main(['-s', 'test_parametrize.py'])

运行结果:

从运行结果中可以看到test_b方法被执行了三遍,说明参数a,b都已经被参数化。

3、利用函数的返回值进行用例参数化

# file_name: test_parametrize.pyimport pytest# 定义返回参数值的函数def return_test_data(): return [(1, 2), (2, 3), (3, 4)]class Test_D: @pytest.mark.parametrize("a,b", return_test_data()) # 使用函数返回值的方式传入参数值 def test_c(self, a, b): print('\n------------------> test_c has ran, and a = {}, b = {}'.format(a, b)) assert 1if __name__ == '__main__': pytest.main(['-s', 'test_parametrize.py'])

运行结果:

从运行结果中可以看到test_c方法被执行了三遍,这说明使用函数的返回值方式同样可以做到参数化。

4、参数组合

获得多个参数化参数的所有组合,可以堆叠使用参数化装饰器:【每一个参数化装饰器代表参数化测试方法中的一组测试数据】

# file_name: test_parametrize.pyimport pytestclass Test_D: @pytest.mark.parametrize("x", [1, 2]) @pytest.mark.parametrize("y", [3, 4]) def test_d(self, x, y): print("\n------------------> test_d has ran, and x={}, y={}".format(x, y))if __name__ == '__main__': pytest.main(['-s', 'test_parametrize.py'])

运行结果:

从运行结果中可以看到test_d方法被执行了四遍,这是因为参数x和参数y分别被赋予了2个值,组合起来就是2*2=4次,说明装饰器叠加可以获得所有参数的组合。

二、参数化@pytest.mark.parametrize装饰器中的indirect参数使用

① indirect 参数一般与pytest中的fixture函数中的 request 组合使用。

②当 indrect=True 时,argnames则要传入fixture函数名称,不再是一个普通参数,而是要被调用的fixture函数,argvalues则是要给这个fixture函数传的值。

③用法其实与 @pytest.fixture(params) 一样,但使用了 @pytest.mark.parametrize 相当于参数化了fixture函数,而不是只有固定的一套数据传入使用。

实例1:【因为参数化装饰器的参数 indirect=Ture ,所以pytest测试框架将login_r当作函数执行,且将test_user_data列表作为参数传入到login_r函数中】

import pytesttest_user_data = ['Tom', 'Jerry']# 方法名作为参数@pytest.fixture(scope='module')def login_r(request): user = request.param # 通过 request.param 获取测试参数 print(f" 登录用户: {user}") return user@pytest.mark.parametrize("login_r", test_user_data, indirect=True)def test_login(login_r): a = login_r print(f"测试用例中 login_r 函数 的返回值; {a}") assert a != ""

运行结果:

实例2:单fixture单值(通过列表)

import pytest@pytest.fixture()def login(request): user = request.param print("传入的用户名为:{}".format(user)) return useruser = ['张三', '李四']@pytest.mark.parametrize('login', user, indirect=True) # 此时测试函数参数化的值为login fixture函数的返回值(参数列表user中存在几组数据就进行了几次参数化)def test_one_param(login): print("测试函数的读到的用户是:{}".format(login))

运行结果:

详细解释:

整个调用过程如下:

实例3:单fixture多值(通过字典)

import pytestuser_info = [ {'user': '张三', 'pwd': 123}, {'user': '李四', 'pwd': 456}]@pytest.fixture()def login(request): user = request.param print("传入的用户名为:{},密码为:{}".format(user['user'], user['pwd'])) return user@pytest.mark.parametrize('login', user_info, indirect=True)def test_one_param(login): print("测试类的读到的用户是:{} 密码是:{}".format(login['user'], login['pwd']))

运行结果:

实例4:传多fixture多值(通过嵌套元组的列表)

import pytest# 一个@pytest.mark.parametrize使用多个fixture,传入的数据要是嵌套了元组的列表user_info = [ ('张三', 123), ('李四', 'pwd')]@pytest.fixture()def login_user(request): user = request.param print("传入的用户名为:{}".format(user)) return user@pytest.fixture()def login_pwd(request): pwd = request.param print("密码为:{}".format(pwd)) return pwd@pytest.mark.parametrize('login_user,login_pwd', user_info, indirect=True)def test_one_param(login_user, login_pwd): print("测试类的读到的用户是:{} 密码是:{}".format(login_user, login_pwd))

运行结果:

实例5:叠加fixture(单值列表,执行次数笛卡尔集 N*M)

import pytestuser = ['张三', '李四']pwd = [124, 345]@pytest.fixture()def login_user(request): user = request.param print("传入的用户名为:{}".format(user)) return user@pytest.fixture()def login_pwd(request): pwd = request.param print("密码为:{}".format(pwd)) return pwd@pytest.mark.parametrize('login_pwd', pwd, indirect=True)@pytest.mark.parametrize('login_user', user, indirect=True)def test_one_param(login_user, login_pwd): print("测试类的读到的用户是:{} 密码是:{}".format(login_user, login_pwd))

运行结果:

三、参数化@pytest.mark.parametrize装饰器中的scope参数使用

① scope 参数的作用范围取值与fixture函数的scope一致,且hi有当 indirect=True 才会被使用。

② scope 参数的作用范围会覆盖fixture函数的scope范围,如果同一个被调用的fixture函数有多个parametrize定义了scope,取第一条的范围。

实例:

import pytest@pytest.fixture(scope='class')def login_user(request): user = request.param print("传入的用户名为:{}".format(user)) return user@pytest.fixture(scope='class')def login_pwd(request): pwd = request.param print("密码为:{}".format(pwd)) return pwdclass TestCase: userinfo = [ ('张三', 123) ] ids = ["case{}".format(i) for i in range(len(userinfo))] @pytest.mark.parametrize('login_user,login_pwd', userinfo, ids=ids, indirect=True, scope='function') def test_one_param(self, login_user, login_pwd): print("测试类的读到的内容是{}{}".format(login_user, login_pwd)) @pytest.mark.parametrize('login_user,login_pwd', userinfo, ids=ids, indirect=True, scope='function') def test_one_param2(self, login_user, login_pwd): print("测试类的读到的内容是{}{}".format(login_user, login_pwd))

运行结果:

①小于fixture函数的scope范围:

②大于fixture函数的scope范围:

③多个SCOPE范围为先执行的:

与③相比调整一下顺序:

四、参数化@pytest.mark.parametrize加mark标记跳过执行其中一组或者多组测试数据(标记同一的测试方法中的子用例,并在子用例上做mark操作:xfail,skip等等)

需求:pytest 使用  @pytest.mark.parametrize 对测试用例进行参数化的时候,当存在多组测试数据时,需要对其中的一组或者多组测试数据加标记跳过执行,可以用 pytest.param 实现。

pytest.param用法:

参数:

① param values :按顺序传参数集值的变量args

② keyword marks  : marks关键字参数,要应用于此参数集的单个标记或标记列表。

③ keyword str id : id字符串关键字参数,测试用例的id属性【测试用例名】

源码:

def param(*values, **kw): """Specify a parameter in `pytest.mark.parametrize`_ calls or :ref:`parametrized fixtures `. .. code-block:: python @pytest.mark.parametrize("test_input,expected", [ ("3+5", 8), pytest.param("6*9", 42, marks=pytest.mark.xfail), ]) def test_eval(test_input, expected): assert eval(test_input) == expected :param values: variable args of the values of the parameter set, in order. :keyword marks: a single mark or a list of marks to be applied to this parameter set. :keyword str id: the id to attribute to this parameter set. """ return ParameterSet.param(*values, **kw)

实例1:xfail标记同一测试方法的子用例

import pytest@pytest.mark.parametrize("test_input,expected", [ ("3+5", 8), pytest.param("6*9", 42, marks=pytest.mark.xfail),])def test_eval(test_input, expected): assert eval(test_input) == expected

运行结果:

实例2:skip标记同一测试方法的子用例

import pytest@pytest.mark.parametrize("user,psw", [("student", "123456"), ("teacher", "abcdefg"), pytest.param("admin", "我爱中华!", marks=pytest.mark.skip(reason='跳过原因')) ])def test_login(user, psw): print(user + " : " + psw) assert 1 == 1

运行结果:

实例3:类比实例2与实例3子用例参数化的区别

import pytest@pytest.mark.parametrize("number", [pytest.param("1"), pytest.param("2"), pytest.param("3", marks=pytest.mark.skip(reason='该参数未准备好'))])def test_login1(number): print(number) assert 1 == 1

运行结果:

实例4:

import pytest@pytest.mark.parametrize("user,psw", [pytest.param("admin1", "123456"), pytest.param("admin2", "abcdefg"), pytest.param("admin3", "higklmn", marks=pytest.mark.skip('此用户的登录信息还没有初始化,不可使用'))])def test_login1(user, psw): print(user + " : " + psw) assert 1 == 1

运行结果:

五、参数化@pytest.mark.parametrize装饰器中的id参数与ids参数使用

id参数需要参照ids参数并加以区分:pytest参数化自定义测试用例标题【@pytest.mark.parametrize(ids=XXX)】

①id参数是给用例添加标题内容,没加id参数的时候,用例会默认拿请求的参数当用例标题;如实例1

②id参数是指单条参数化测试用例数据时,分别为同一测试方法中的每一条测试用例进行命名;ids参数是指多条参数化测试用例数据时,ids参数传入一个列表或者元组,分别为同一测试方法中的所有测试用例进行命名。如实例2、实例3

实例1:

import pytest@pytest.mark.parametrize("user,psw", [pytest.param("admin1", "abcdefg"), pytest.param("admin2", "123456"), pytest.param("admin3", "qwerty", marks=pytest.mark.skip)])def test_login1(user, psw): print(user + " : " + psw) assert 1 == 1

运行结果:

实例2:

import pytest@pytest.mark.parametrize("user,psw", [pytest.param("admin1", "abcdefg", id="第一条测试用例名字"), pytest.param("admin2", "123456", id="第二条测试用例名字"), pytest.param("admin3", "qwerty", marks=pytest.mark.skip, id="第三条测试用例名字")])def test_login1(user, psw): print(user + " : " + psw) assert 1 == 1

运行结果:

实例3:

import pytest@pytest.mark.parametrize("user,psw", argvalues=[("admin1", "abcdefg"), ("admin2", "123456"), ("admin3", "qwerty")], ids=["第一条测试用例名字", "第二条测试用例名字", "第三条测试用例名字"])def test_login1(user, psw): print(user + " : " + psw) assert 1 == 1

运行结果:

去期待陌生,去拥抱惊喜。


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:Java多文件生成并压缩下载功能(思路详解)
下一篇:pytest的软断言-断言失败后仍然执行后续代码(插件:pytest-assume)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~