Pytest框架之 - 参数化

  • 作者:lwj
  • 分类:Pytest
  • 发表日期:2020-11-03 21:19:01
  • 阅读(393)
  • 评论(0)

自动化测试中一个测试用例对应一个测试点, 通常一组测试数据无法完全覆盖所有测试范围, 所以需要参数化来传递多组数据。Pytest的参数化有两种实现方式

pytest.fixture

fixture的参数params可以实现参数化的

参数paramslist类型,提供参数数据(参数化),供调用标记方法的函数使用

参数ids:配合params参数使用的, 如果没有设置params参数,那么ids毫无意义; ids参数是给每一项params参数设置自定义名称用的; params参数值包含的列表有多少项值,那么ids参数就必须对应有多少项值

fixture返回值

#!/usr/bin/python3
# coding=utf-8
# Author: 文

import pytest

@pytest.fixture()
def need_data():
    return 2        # 返回数字2

class Test_One:
    def test_a(self, need_data):                    # need_data返回值2
        print("------->test_a")
        print("need_data等于" + str(need_data))
        assert need_data != 3                       # 拿到返回值做一次断言

if __name__ == "__main__":
    pytest.main(["-s", "test_two.py::Test_One"])

执行结果如下:

F:\Python3.6.5\python.exe E:/xxx/test_two.py
============================= test session starts =============================
platform win32 -- Python 3.6.5, pytest-6.1.1, py-1.9.0, pluggy-0.13.1
rootdir: E:\xxx, configfile: pytest.ini
plugins: html-2.1.1, metadata-1.10.0
collected 1 item
test_two.py ------->test_a
need_data等于2
.
============================== 1 passed in 0.37s ==============================
Process finished with exit code 0

fixture参数化

#!/usr/bin/python3
# coding=utf-8
# Author: 文

import pytest

@pytest.fixture(params=['aaa', 'bbb', 'ccc'], ids=["data-1", "data-2", "data-3"])
def parameterization(request):                  # 传入参数request 系统封装参数
    return request.param                        # 取列表中单个值,默认的取值方式

class Test_One():
    def test_b(self, parameterization):         # 获得返回值 request.param
        print("------> test_b")
        print("参数化参数:" + parameterization)

if __name__ == "__main__":
    pytest.main(["-s", "-v", "test_two.py::Test_One"])

执行结果如下:

F:\Python3.6.5\python.exe E:/xxx/test_two.py
============================= test session starts =============================
platform win32 -- Python 3.6.5, pytest-6.1.1, py-1.9.0, pluggy-0.13.1 -- F:\Python3.6.5\python.exe
cachedir: .pytest_cache
metadata: {'Python': '3.6.5', 'Platform': 'Windows-10-10.0.17763-SP0', 'Packages': {'pytest': '6.1.1', 'py': '1.9.0', 'pluggy': '0.13.1'}, 'Plugins': {'html': '2.1.1', 'metadata': '1.10.0'}, 'JAVA_HOME': 'F:\\java\\jdk1.8.0_181'}
rootdir: E:\xxx, configfile: pytest.ini
plugins: html-2.1.1, metadata-1.10.0
collecting ... collected 3 items
test_two.py::Test_One::test_b[data-1] ------> test_b
参数化参数:aaa
PASSED
test_two.py::Test_One::test_b[data-2] ------> test_b
参数化参数:bbb
PASSED
test_two.py::Test_One::test_b[data-3] ------> test_b
参数化参数:ccc
PASSED
============================== 3 passed in 0.02s ==============================
Process finished with exit code 0

pytest.mark.parametrize

参数argnames:参数名字,字符串格式,如:"str1, str2, str3"  【需要用逗号分隔】

参数argvalues参数值列表必须是列表,如:["data1", "data2", "data3"]

参数ids:用例的ID,字符串列表,如:["name01", "name02"]   标识每一个测试用例, 自定义测试数据结果的显示增加可读性

参数indirect:为True的时候将变量当做函数执行, 为False的时候只是当做变量来引用了;默认为False

#!/usr/bin/python3
# coding=utf-8
# Author: 文

import pytest

class Test_One():
    @pytest.mark.parametrize(argnames="a, b", argvalues=[(1, 2),(3, 0)], ids=["name01", "name02"])
    def test_c(self, a, b):
        print("==========> test_c")
        print(a+b)
        assert a + b == 3

if __name__ == "__main__":
    pytest.main(["-s", "-v", "test_three.py::Test_One"])

执行结果如下:

F:\Python3.6.5\python.exe E:/xxx/test_three.py
============================= test session starts =============================
platform win32 -- Python 3.6.5, pytest-6.1.1, py-1.9.0, pluggy-0.13.1 -- F:\Python3.6.5\python.exe
cachedir: .pytest_cache
metadata: {'Python': '3.6.5', 'Platform': 'Windows-10-10.0.17763-SP0', 'Packages': {'pytest': '6.1.1', 'py': '1.9.0', 'pluggy': '0.13.1'}, 'Plugins': {'html': '2.1.1', 'metadata': '1.10.0'}, 'JAVA_HOME': 'F:\\java\\jdk1.8.0_181'}
rootdir: E:\xxx, configfile: pytest.ini
plugins: html-2.1.1, metadata-1.10.0
collecting ... collected 2 items
test_three.py::Test_One::test_c[name01] ==========> test_c
3
PASSED
test_three.py::Test_One::test_c[name02] ==========> test_c
3
PASSED
============================== 2 passed in 0.98s ==============================
Process finished with exit code 0

参数indirect - parametrize与fixtrue组合使用

indirectFalse:参数argnames为参数名字 (如下代码中的测试用例"test_d")

indirectTrue:参数argnames为可执行的函数名(fixtruename), 传参到测试用例的参数为该函数的返回值(如下代码中的测试用例"test_e")

#!/usr/bin/python3
# coding=utf-8
# Author: 文

import pytest

data = [{"username": "lwj", "password": "2020-11-11"}, {"username": "zdk", "password": ""}]

class Test_Three():
    @pytest.fixture()
    def default(self, request):
        user = request.param['username']
        psw = request.param['password']
        print('login username is {0}, login password is {1}'.format(user, psw))
        if psw:                 # psw存在值则返回True 否则返回False
            return True
        else:
            return False

    # indirect为False 按普通参数化传参 default为参数的变量名
    @pytest.mark.parametrize(argnames="default", argvalues=data, indirect=False)
    def test_d(self, default):
        print("==========> test_d")
        print("测试参数为:", default)

    # indirect为True default为可执行的函数名 data为参数传入default函数中去执行 用例参数为函数default的返回值
    @pytest.mark.parametrize(argnames="default", argvalues=data, indirect=True)
    def test_e(self, default):
        print("==========> test_e")
        print("测试参数为:", default)

if __name__ == "__main__":
    pytest.main(["-rs", "test_three.py::Test_Three"])

执行结果如下:

F:\Python3.6.5\python.exe E:/xxx/test_three.py
============================= test session starts =============================
platform win32 -- Python 3.6.5, pytest-6.1.1, py-1.9.0, pluggy-0.13.1
rootdir: E:\xxx, configfile: pytest.ini
plugins: html-2.1.1, metadata-1.10.0
collected 4 items
test_three.py ==========> test_d
测试参数为: {'username': 'lwj', 'password': '2020-11-11'}
.==========> test_d
测试参数为: {'username': 'zdk', 'password': ''}
.
login username is lwj, login password is 2020-11-11
==========> test_e
测试参数为: True
.
login username is zdk, login password is 
==========> test_e
测试参数为: False
.
============================== 4 passed in 0.01s ==============================
Process finished with exit code 0

:"笛卡尔积" - 多个参数化装饰器

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

#!/usr/bin/python3
# coding=utf-8
# Author: 文

import pytest

class Test_One():
    data_1 = [1, 2, 3]
    data_2 = ['a', 'b']
    @pytest.mark.parametrize('a', data_1)
    @pytest.mark.parametrize('b', data_2)
    def test_parametrize_1(self, a, b):
        print(f'笛卡尔积 测试数据为 : {a},{b}')

if __name__ == "__main__":
    pytest.main(["-s", "-v", "test_three.py::Test_One"])

执行结果如下:

F:\Python\python.exe E:/xxx/test_three.py
============================= test session starts =============================
platform win32 -- Python 3.6.5, pytest-6.1.1, py-1.9.0, pluggy-0.13.1 -- F:\Python\python.exe
cachedir: .pytest_cache
metadata: {'Python': '3.6.5', 'Platform': 'Windows-10-10.0.17763-SP0', 'Packages': {'pytest': '6.1.1', 'py': '1.9.0', 'pluggy': '0.13.1'}, 'Plugins': {'html': '2.1.1', 'metadata': '1.10.0'}, 'JAVA_HOME': 'F:\\java\\jdk1.8.0_181'}
rootdir: E:\xxx, configfile: pytest.ini
plugins: html-2.1.1, metadata-1.10.0
collecting ... collected 6 items
test_three.py::Test_One::test_parametrize_1[a-1] 笛卡尔积 测试数据为 : 1,a
PASSED
test_three.py::Test_One::test_parametrize_1[a-2] 笛卡尔积 测试数据为 : 2,a
PASSED
test_three.py::Test_One::test_parametrize_1[a-3] 笛卡尔积 测试数据为 : 3,a
PASSED
test_three.py::Test_One::test_parametrize_1[b-1] 笛卡尔积 测试数据为 : 1,b
PASSED
test_three.py::Test_One::test_parametrize_1[b-2] 笛卡尔积 测试数据为 : 2,b
PASSED
test_three.py::Test_One::test_parametrize_1[b-3] 笛卡尔积 测试数据为 : 3,b
PASSED
============================== 6 passed in 0.02s ==============================
Process finished with exit code 0

 

觉得不错,支持一下!

提交评论

您尚未登录,登录之后方可评论~ 登录 or 注册

评论列表

暂无评论
返回顶部

建议反馈

1. 可在博文底部留言评论

2. 发邮件到i_suichuan@163.com