pytest:参数化用例
一、如果待测试的输入和输出是一组数据,可以把测试数据组织起来用不同的测试数据调用相同的测试方法。参数化顾名思义就是把不同的参数,写到一个集合里,然后程序会自动取值运行用例,直到集合为空便结束。pytest中可以使用@pytest.mark.parametrize来参数化。
使用parametrize实现参数化
parametrize()方法源码:
def parametrize(self,argnames,argvalues,indirect=False,ids=None,scope=None)
主要参数说明
----argsnames:参数名 是个字符串如中间用逗号分隔则表示为多个参数名
----argvalues:参数值 参数组成的列表 列表中的几个元素就会生成几条用例
使用方法:
---使用 @pytest.mark.paramtrize()装饰器测试方法
----parametrize('data',param)中的 data是自定义的参数名,param是引入的参数列表
----将自定义的参数名data作为参数传给测试用例test_func
---然后就可以在测试用例内部使用data的参数了
创建测试用例,传入三组参数,每组两个元素,判断每组参数里面表达式和值是否相等代码如下:
#!/usr/bin/env python # _*_coding: utf-8 _*_ import pytest @pytest.mark.parametrize("test_input,expected", [("3+5", 8), ("2 + 5", 7), ("7 * 5", 30)]) def test_eval(test_input, expected): assert eval(test_input) == expected
运行结果:
Testing started at 15:17 ... C:\Python\python.exe "C:\Program Files\JetBrains\PyCharm Community Edition 2019.1\helpers\pycharm\_jb_pytest_runner.py" --target test_parametrize1.py::test_eval Launching pytest with arguments test_parametrize1.py::test_eval in C:\Users\wanwen\PycharmProjects\vigo\xuexi\20210123 ============================= test session starts ============================= platform win32 -- Python 3.8.0, pytest-5.4.3, py-1.9.0, pluggy-0.13.1 rootdir: C:\Users\wanwen\PycharmProjects\vigo\xuexi\20210123 plugins: html-2.1.1, metadata-1.11.0, ordering-0.6collected 3 items test_parametrize1.py ..F test_parametrize1.py:6 (test_eval[7 * 5-30]) 35 != 30 Expected :30 Actual :35 <Click to see difference> test_input = '7 * 5', expected = 30 @pytest.mark.parametrize("test_input,expected", [("3+5", 8), ("2 + 5", 7), ("7 * 5", 30)]) def test_eval(test_input, expected): > assert eval(test_input) == expected E AssertionError: assert 35 == 30 E + where 35 = eval('7 * 5') test_parametrize1.py:9: AssertionError Assertion failed [100%] ================================== FAILURES =================================== _____________________________ test_eval[7 * 5-30] _____________________________ test_input = '7 * 5', expected = 30 @pytest.mark.parametrize("test_input,expected", [("3+5", 8), ("2 + 5", 7), ("7 * 5", 30)]) def test_eval(test_input, expected): > assert eval(test_input) == expected E AssertionError: assert 35 == 30 E + where 35 = eval('7 * 5') test_parametrize1.py:9: AssertionError =========================== short test summary info =========================== FAILED test_parametrize1.py::test_eval[7 * 5-30] - AssertionError: assert 35 ... ========================= 1 failed, 2 passed in 0.12s ========================= Process finished with exit code 0 Assertion failed Assertion failed
整个执行过程中,pytest将参数列表
[("3+5", 8), ("2 + 5", 7), ("7 * 5", 30)]中的三组数据取出来,每组数据生成一条测试用例,并且将每组数据中的两个元素分别赋值到方法中,
作为测试方法的参数有测试用例使用
二、多次使用parametrize
同一个测试用例还可以同时添加多个@pytest.mark.parametrize装饰器,多个
parametrize的所有元素互相组合(类似笛卡尔积)生成大量的测试用例
场景:比如登入场景,用户输入情况有n种,密码的输入情况有M种希望验证用户名和密码就会涉及到n*m种组合的测试用例,
如果把这些数据一一列出来工作量也是非常大的。pytest提供了一种参数化方式
将多组测试数据组合生成大量的测试用例
实例代码如下:
#!/usr/bin/env python # _*_coding: utf-8 _*_ import pytest @pytest.mark.parametrize("x", [1, 2]) @pytest.mark.parametrize("y", [8, 10, 11]) def test_foo(x, y): print(f"测试数据组合x:{x},y:{y}")
运行结果:
Testing started at 15:31 ... C:\Python\python.exe "C:\Program Files\JetBrains\PyCharm Community Edition 2019.1\helpers\pycharm\_jb_pytest_runner.py" --target test_parametrize2.py::test_foo Launching pytest with arguments test_parametrize2.py::test_foo in C:\Users\wanwen\PycharmProjects\vigo\xuexi\20210123 ============================= test session starts ============================= platform win32 -- Python 3.8.0, pytest-5.4.3, py-1.9.0, pluggy-0.13.1 rootdir: C:\Users\wanwen\PycharmProjects\vigo\xuexi\20210123 plugins: html-2.1.1, metadata-1.11.0, ordering-0.6collected 6 items test_parametrize2.py [100%] ============================== 6 passed in 0.04s ============================== Process finished with exit code 0 .测试数据组合x:1,y:8 .测试数据组合x:2,y:8 .测试数据组合x:1,y:10 .测试数据组合x:2,y:10 .测试数据组合x:1,y:11 .测试数据组合x:2,y:11
分析如上运行结果,测试方法test_foo()添加了两个@pytest.mark.parametrize()装饰器,两个装饰器分别提供两个参数值得列表,2*3=6种结合,pytest便会生成6条
测试用例。在测试中使用这种参数自由组合,可以实现全面测.
三、@pytest.fixture 与 @pytest.mark.parametrize结合实现参数化
parametrize源码:
def parametrize(self,argnames,argvalues,indirect=False,ids=None,scope=None):
indirect参数设置为true,pytest会把argnames当做函数去执行,将argvalues作为参数传入到argnames这个函数里
实例代码如下:
#!/usr/bin/env python # _*_coding: utf-8 _*_ import pytest test_user_data = ['Tome', 'Jerry'] @pytest.fixture(scope="module") def login_r(request): user = request.param print(f"\n 登入用户:{user}") return user @pytest.mark.parametrize("login_r", test_user_data, indirect=True) def test_login(login_r): a = login_r print(f"测试用例中login的返回值:{a}") assert a != ""
运行结果如下:
Testing started at 15:53 ... C:\Python\python.exe "C:\Program Files\JetBrains\PyCharm Community Edition 2019.1\helpers\pycharm\_jb_pytest_runner.py" --path C:/Users/wanwen/PycharmProjects/vigo/xuexi/20210123/test_parametrize3.py Launching pytest with arguments C:/Users/wanwen/PycharmProjects/vigo/xuexi/20210123/test_parametrize3.py in C:\Users\wanwen\PycharmProjects\vigo\xuexi\20210123 ============================= test session starts ============================= platform win32 -- Python 3.8.0, pytest-5.4.3, py-1.9.0, pluggy-0.13.1 rootdir: C:\Users\wanwen\PycharmProjects\vigo\xuexi\20210123 plugins: html-2.1.1, metadata-1.11.0, ordering-0.6collected 2 items test_parametrize3.py [100%] ============================== 2 passed in 0.03s ============================== Process finished with exit code 0
上面的结果可以看出,当indirect=True时,会将login_r作为参数,test_user_data被当作参数传入到login_r方法中生成多条测试用例,通过return将结果返回,当调用login_r可以获取到login_r这个方法的返回数据。