@pytest.mark.parametrize 允许在测试函数或类中定义多组参数和 fixtures。

参数化场景:

只有测试数据和预期结果不一样,但操作步骤是一样的测试用例是可以用上参数化的。

 

创建test_parametrize.py文件

示例一:未参数化

1、脚本代码:



#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
微信公众号:AllTests软件测试
"""

# 未参数化
def test_case1():
assert 3 + 4 == 9

def test_case2():
assert 2 + 5 == 7

def test_case3():
assert 6 * 9 == 48


可以看到,三个用例都是先计算,然后断言某个值,重复写三个类似的用例有些冗余。

2、运行结果:

Python测试框架pytest(17)参数化parametrize_pytest

Python测试框架pytest(17)参数化parametrize_pytest_02

 

示例二:参数化(优化代码)

1、脚本代码:



#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
微信公众号:AllTests软件测试
"""

import pytest

# 参数化(优化代码)
@pytest.mark.parametrize("test_input, expected", [("3+4", 9), ("2+5", 7), ("6*9", 48)])
def test_eval(test_input, expected):
print(f"测试数据{test_input}, 预期结果{expected}")
assert eval(test_input) == expected


2、运行结果:

可以看到,只有一条用例,但是利用参数化输入三组不同的测试数据和预期结果,最终执行的测试用例数还是3条,可以节省很多代码。

Python测试框架pytest(17)参数化parametrize_微信公众号_03

Python测试框架pytest(17)参数化parametrize_微信公众号_04

 

1、参数 



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


主要参数:

(1)argnames:参数名,是个字符串,如中间用逗号分隔则表示为多个参数名。

1、创建test_parametrize2.py文件

参数名也可以是list或者tuple里的字符串。

脚本代码:



#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
微信公众号:AllTests软件测试
"""

import pytest

@pytest.mark.parametrize(["name", "pwd"], [("AllTests", "123456"), ("qq", "85135506")])
def test_case1(name, pwd):
print(name, pwd)

@pytest.mark.parametrize(("name", "pwd"), [("wangmcn", "567890"), ("admin", "123qwe")])
def test_case2(name, pwd):
print(name, pwd)

@pytest.mark.parametrize("name, pwd", [("root", "root"), ("guest", "guest")])
def test_case3(name, pwd):
print(name, pwd)


2、运行结果:

Python测试框架pytest(17)参数化parametrize_pytest_05

(2)argvalues:参数值,参数组成的列表,列表中有几个元素,就会生成几条用例。

1、创建test_parametrize3.py文件

脚本代码:



#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
微信公众号:AllTests软件测试
"""

import pytest

# 如果只有一个参数,里面则是值的列表
@pytest.mark.parametrize("name", ["AllTests", "wangmcn", "admin"])
def test_case1(name):
print(name)

# 如果有多个参数,list包含tuple
@pytest.mark.parametrize(["name", "pwd"], [("AllTests", "123456"), ("qq", "85135506")])
def test_case2(name, pwd):
print(name, pwd)

# 如果有多个参数,tuple包含list
@pytest.mark.parametrize(("name", "pwd"), (["wangmcn", "567890"], ["admin", "123qwe"]))
def test_case3(name, pwd):
print(name, pwd)

# 如果有多个参数,list包含list
@pytest.mark.parametrize("name, pwd", [["root", "root"], ["guest", "guest"]])
def test_case4(name, pwd):
print(name, pwd)


2、运行结果:

Python测试框架pytest(17)参数化parametrize_测试开发_06

(3)ids:用例的ID。传一个字符串列表,可以标识每一个测试用例,自定义测试数据结果的显示,为了增加可读性。

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

1、创建test_parametrize8.py文件

脚本代码:



#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
微信公众号:AllTests软件测试
"""

import pytest

my_data = [(1, 2, 3), (4, 5, 9)]

ids = ["a:{} + b:{} = expect:{}".format(a, b, expect) for a, b, expect in my_data]

@pytest.mark.parametrize("a, b, expect", my_data, ids=ids)
def test_parametrize_case(a, b, expect):
print("测试数据为{}-{}".format(a, b))
assert a + b == expect


2、运行结果:

Python测试框架pytest(17)参数化parametrize_软件测试_07

Python测试框架pytest(17)参数化parametrize_测试开发_08

 

2、装饰测试类 

1、创建test_parametrize2.py文件

脚本代码:



#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
微信公众号:AllTests软件测试
"""

import pytest

my_data = [(1, 2, 3), (4, 5, 9)]

@pytest.mark.parametrize("a, b, expect", my_data)
class TestParametrize:

def test_parametrize_case1(self, a, b, expect):
print("\n测试用例case1 测试数据为{}+{}".format(a, b))
assert a + b == expect

def test_parametrize_case2(self, a, b, expect):
print("\n测试用例case2 测试数据为{}+{}".format(a, b))
assert a + b == expect


2、运行结果:

当装饰器 @pytest.mark.parametrize 装饰测试类时,会将数据集合传递给类的所有测试用例方法。

Python测试框架pytest(17)参数化parametrize_微信公众号_09

Python测试框架pytest(17)参数化parametrize_测试框架_10

 

3、多个参数化装饰器

一个函数或一个类可以装饰多个 @pytest.mark.parametrize

当参数化装饰器有很多个的时候,用例数等于n(个)*n(个)*n(个)*n(个)*....

 

1、创建test_parametrize5.py文件。

脚本代码:



#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
微信公众号:AllTests软件测试
"""

import pytest

my_data_1 = [1, 2, 3]
my_data_2 = ["a", "b"]

@pytest.mark.parametrize("a", my_data_1)
@pytest.mark.parametrize("b", my_data_2)
def test_parametrize_case(a, b):
print(f"测试数据为:{a},{b}")


2、运行结果:

参数a的数据有3个,参数b的数据有2个,所以最终的用例数有3*2=6条。

Python测试框架pytest(17)参数化parametrize_pytest_11

Python测试框架pytest(17)参数化parametrize_软件测试_12

 

4、参数化(传入字典数据) 

1、创建test_parametrize6.py文件

数据类型为字典

脚本代码:



#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
微信公众号:AllTests软件测试
"""

import pytest

my_data = (
{
"user": "AllTests",
"pwd": "123456"
},
{
"user": "wangmcn",
"pwd": "567890"
}
)

@pytest.mark.parametrize('dic', my_data)
def test_parametrize_case(dic):
print(f'测试数据为\n{dic}')
print(f'user:{dic["user"]}, pwd:{dic["pwd"]}')


2、运行结果:

Python测试框架pytest(17)参数化parametrize_测试框架_13

Python测试框架pytest(17)参数化parametrize_测试开发_14

 

5、标记参数化

pytest.param 可以传三种参数:

  • param values - 参数集值的变量 args,按顺序排列。
  • keyword marks - marks 关键字标记,要应用于此参数集的单个标记或标记列表。
  • keyword str id - 参数集的属性 id。

 

示例一:

1、创建test_parametrize7.py文件。

脚本代码:



#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
微信公众号:AllTests软件测试
"""

import pytest

@pytest.mark.parametrize("test_input, expected", [
("3+5", 8),
("2+4", 6),
pytest.param("6*9", 45, marks=pytest.mark.xfail),
pytest.param("6*6", 50, marks=pytest.mark.skip)
])
def test_case(test_input, expected):
assert eval(test_input) == expected


2、运行结果:

Python测试框架pytest(17)参数化parametrize_测试开发_15

Python测试框架pytest(17)参数化parametrize_软件测试_16

 

示例二:

1、创建test_parametrize7_2.py文件。

脚本代码:



#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
微信公众号:AllTests软件测试
"""

import pytest

@pytest.mark.parametrize("test_input, expected", [
pytest.param("3+5", 8, id="case1"),
pytest.param("2+4", 6, id="case2"),
pytest.param("6*9", 45, marks=pytest.mark.xfail, id="case3"),
pytest.param("6*6", 50, marks=pytest.mark.skip, id="case4")
])
def test_case(test_input, expected):
assert eval(test_input) == expected


2、运行结果:

Python测试框架pytest(17)参数化parametrize_软件测试_17

Python测试框架pytest(17)参数化parametrize_软件测试_18

 

6、解决unicode编码问题 

使用 @pytest.mark.parametrize 参数化的时候,加 ids 参数用例描述有中文时,在控制台输出会显示 unicode 编码问题,中文不能正常显示。

解决方法:使用 pytest_collection_modifyitems 钩子函数,对输出的 item.name 和 item.nodeid 重新编码即可。

 

1、创建test_parametrize9.py文件

脚本代码:



#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
微信公众号:AllTests软件测试
"""

import pytest

def login(username, password):
"登陆操作"
return {"code": 0, "msg": "success!"}

my_data = [
({"username": "AllTests", "password": "123456"}, "success!"),
({"username": "Admin123", "password": "123456"}, "success!"),
({"username": "Admin456", "password": "123456"}, "success!"),
]

ids = [
"输入正确a账号,正确密码,登录成功",
"输入正确b账号,正确密码,登录成功",
"输入正确c账号,正确密码,登录成功",
]

@pytest.mark.parametrize("input_data, expected", my_data, ids=ids)
def test_login(input_data, expected):
"测试用例-登陆"
result = login(input_data["username"], input_data["password"])
assert result["msg"] == expected


2、打开命令行,输入执行命令



pytest -v test_parametrize9.py


运行结果:

控制台输出中文时显示unicode编码问题。

Python测试框架pytest(17)参数化parametrize_pytest_19

3、解决ids参数用例描述为中文时,控制台输出显示unicode编码问题。

在项目的根目录或与用例同级目录下,创建conftest.py文件

脚本代码:



#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
微信公众号:AllTests软件测试
"""

def pytest_collection_modifyitems(items):
for item in items:
item.name = item.name.encode("utf-8").decode("unicode_escape")
# print(item.nodeid)
item._nodeid = item.nodeid.encode("utf-8").decode("unicode_escape")


重新执行用例,运行结果:

控制台输出中文时显示正常。

Python测试框架pytest(17)参数化parametrize_软件测试_20

 

 ​