pytest实战技巧之参数化应用_pytest 数据驱动框架 参数化,2024最新阿里软件测试面试流程

42 阅读5分钟

   assert (sub in s) == expected


这里我们将参数名称s、sub和expected分别和参数值列表中的元组对应起来,这样就可以更直观地理解 每个参数的含义。




> 

> 注意,参数名称列表也可以是一个字符串,多个参数名称之间用逗号隔开,例如:"a, b, expected" 

> 

> 

> 




* **参数化装饰器嵌套**


有时我们需要对多个参数进行组合,这时可以使用参数化装饰器的嵌套。例如,我们有一个函数用来测试两个字符串连接后的结果是否正确,可以这样写:



@pytest.mark.parametrize("s1", ["hello", "world"])

@pytest.mark.parametrize("s2", ["python", "pytest"])

def test_concat(s1, s2):

   assert concat(s1, s2) == s1 + s2


这里我们先用一个参数化装饰器指定s1参数的取值范围,然后在这个装饰器内部再嵌套一个参数化装饰器,指定s2参数的取值范围。这样,pytest就会自动运行测试函数四次,每次用一个s1和一个s2的组合 来测试函数的正确性。 


* **参数化函数**


**有时我们需要动态生成参数值列表,这时可以使用参数化函数。例如,我们有一个函数用来测试一个整数是否为质数,可以这样写:**



def is_prime(n):

   if n < 2:

      return False

   for i in range(2, int(n ** 0.5) + 1):

      if n % i == 0:

         return False

   return True

@pytest.mark.parametrize("n", range(10))

def test_is_prime(n):

   assert is_prime(n) == (n in [2, 3, 5, 7])


这里我们使用了Python内置的range函数来生成一个整数序列,然后将这个序列作为参数值列表传给了参数化装饰器。这样,pytest就会自动运行测试函数十次,每次用一个整数来测试函数的正确性。


* **从文件读取参数**


**有时我们需要从外部文件中读取参数值列表,这时可以使用pytest的fixture机制。例如,我们有一个CSV文件,包含了多组数据,每组数据都是一个整数和一个字符串,用逗号隔开。我们希望用这些数据 来测试一个函数,可以这样写:**



import csv

import pytest

@pytest.fixture(scope="module")

def data():

   with open("test_data.csv") as f:

      reader = csv.reader(f)

      return list(reader)

@pytest.mark.parametrize("n, s", data())

def test_func(n, s):

   assert func(n, s) == ...


这里我们定义了一个fixture函数data,用来读取CSV文件中的数据,并返回一个列表,每个元素都是一 个包含两个值的元组。然后在测试函数的参数化装饰器中,使用data()来获取这个列表,并将其中的元 组分别赋值给n和s两个参数。这样,pytest就会自动运行测试函数多次,每次用一个元组中的数据来测 试函数的正确性。 



**03、参数化的高级技巧**


除了上面介绍的基本用法和多种方式,pytest参数化还有一些高级技巧,可以帮助我们更灵活地使用这个功能。 


* **动态生成参数名称**


有时我们需要动态生成参数名称,例如根据参数值来生成一个唯一的标识符。这时可以使用pytest的ids 参数,它可以指定每个参数值对应的参数名称。例如,我们有一个函数用来测试两个字符串连接后的长度是否正确,可以这样写:



@pytest.mark.parametrize("s1, s2, expected", [

   ("hello", "world", 10),

   ("pytest", "is awesome", 15),

], ids=["case1", "case2"])

def test_len(s1, s2, expected):

   assert len(concat(s1, s2)) == expected


这里我们使用了ids参数,将每个参数值对应的参数名称指定为了一个字符串,分别 是"case1"和"case2"。这样,pytest就会在测试结果中显示这些参数名称,方便我们查看和分析测试结果。 


* **参数化的组合**


有时我们需要对多个参数进行组合,例如测试一个函数在不同参数组合下的正确性。这时可以使用pytest的product参数化,它可以将多个参数值列表进行组合,生成所有可能的参数组合。


**例如,我们有一个函数用来测试两个整数相乘的结果是否正确,可以这样写:**



@pytest.mark.parametrize("a", [1, 2, 3]) @pytest.mark.parametrize("b", [4, 5, 6])

def test_mul(a, b):

   assert mul(a, b) == a * b

@pytest.mark.parametrize("a, b", product([1, 2, 3], [4, 5, 6]))

def test_mul2(a, b):

   assert mul(a, b) == a * b


这里我们先用两个参数化装饰器分别指定ab的取值范围,然后在测试函数中用ab的乘积来进行断 言。这样,pytest就会自动运行测试函数九次,每次用一个a和一个b的组合来测试函数的正确性。另 外,我们还可以使用product函数来完成同样的功能,它可以将多个参数值列表进行组合,并返回所有可能的参数组合。


* **动态生成参数化装饰器**


有时我们需要根据某些条件动态生成参数化装饰器,例如根据某个配置文件中的参数来决定测试函数的参数取值范围。这时可以使用pytest的fixture机制,动态生成参数化装饰器。


例如,我们有一个配置文件,包含了两个参数**s和n**,分别表示一个字符串和一个整数,我们希望用这些参数来测试一个函数,可 以这样写:



import yaml

import pytest

@pytest.fixture(scope="module")

def config():

   with open("test_config.yaml") as f:

        return yaml.safe_load(f)

@pytest.fixture(scope="module")

   def params(config):

       return [(s, n) for s in config["strings"] for n in config["numbers"]]

def test_func(params):

   for s, n in params:

       assert func(s, n) == ...


这里我们定义了两个fixture函数,config和params。


* config用来读取配置文件中的参数
* params用来根据这些参数动态生成参数值列表


然后在测试函数中,使用params来获取参数值列表,并将其中的元 组分别赋值给s和n两个参数。这样,pytest就会自动运行测试函数多次,每次用一个元组中的数据来测试函数的正确性。 



**04、总结**


![img](https://p9-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/6f9f756135f74f83a3d545e3de61aefe~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg55So5oi3MzIxMjA3NDIwNDUy:q75.awebp?rk3s=f64ab15b&x-expires=1771133777&x-signature=xkcnx42%2BLgmD2cKkg%2B7jRm%2FMW7c%3D)
![img](https://p9-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/a77612742ee74ed498433bfed63047fc~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg55So5oi3MzIxMjA3NDIwNDUy:q75.awebp?rk3s=f64ab15b&x-expires=1771133777&x-signature=ckuWMmnm2CKqQBfAkZtmk7IdOyo%3D)

**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**了解详情》docs.qq.com/doc/DSlVlZExWQ0FRSE9H**