如何在Pytest测试类的parametrize装饰器中使用self属性?
问题:在pytest类测试中使用对象属性实现parametrize
原本的函数式测试可以正常运行:
import pytest from astropy.table import Table @pytest.mark.parametrize('row', Table.read('testcases.fits')) def test_cases(row): my_limit = 5.0 assert abs(row['foo'] - row['bar']) < my_limit
但封装为类后,因为@pytest.mark.parametrize在类定义阶段就会执行,此时类实例尚未创建,self不存在,导致报错NameError: name 'self' is not defined:
import pytest import matplotlib.pyplot as plt from astropy.table import Table class MyTest: def __init__(self): self.testcases = Table.read('testcases.fits') self.my_limit = 5.0 @pytest.mark.parametrize('row', self.testcases) def test_cases(self, row): assert abs(row['foo'] - row['bar']) < self.my_limit def plot(self): plt.plot(self.testcases['foo'], self.testcases['bar'])
解决方案
方法一:将测试用例设为类属性
把testcases和my_limit定义为类属性,类定义阶段就能直接访问,无需依赖实例:
import pytest import matplotlib.pyplot as plt from astropy.table import Table class MyTest: # 类属性,类定义时即可读取 testcases = Table.read('testcases.fits') my_limit = 5.0 @pytest.mark.parametrize('row', testcases) def test_cases(self, row): assert abs(row['foo'] - row['bar']) < self.my_limit def plot(self): plt.plot(self.testcases['foo'], self.testcases['bar'])
适用场景:测试用例固定,不需要动态生成的情况,代码最简洁。
方法二:使用间接参数化+Fixture
通过indirect=True让parametrize调用Fixture,间接获取实例属性:
import pytest import matplotlib.pyplot as plt from astropy.table import Table class MyTest: def __init__(self): self.testcases = Table.read('testcases.fits') self.my_limit = 5.0 @pytest.fixture def row_with_instance(self, request): # 返回测试用例行和当前类实例 return request.param, self @pytest.mark.parametrize( 'row_with_instance', lambda self: self.testcases, indirect=True ) def test_cases(self, row_with_instance): row, self_instance = row_with_instance assert abs(row['foo'] - row['bar']) < self_instance.my_limit def plot(self): plt.plot(self.testcases['foo'], self.testcases['bar'])
适用场景:需要保留实例初始化逻辑(比如动态传入参数创建实例)的情况。
方法三:使用pytest_generate_tests钩子函数
在测试收集阶段动态生成参数,适合复杂场景:
import pytest import matplotlib.pyplot as plt from astropy.table import Table class MyTest: def __init__(self): self.testcases = Table.read('testcases.fits') self.my_limit = 5.0 def test_cases(self, row): assert abs(row['foo'] - row['bar']) < self.my_limit def plot(self): plt.plot(self.testcases['foo'], self.testcases['bar']) # 钩子函数:为指定测试方法生成参数 def pytest_generate_tests(metafunc): # 判断当前测试是否属于MyTest类的test_cases方法 if metafunc.cls is MyTest and metafunc.function.__name__ == "test_cases": # 创建实例并获取测试用例 test_instance = MyTest() metafunc.parametrize('row', test_instance.testcases)
适用场景:需要根据外部条件(如命令行参数)动态调整测试用例的复杂场景。
内容的提问来源于stack exchange,提问作者olebole
相关产品推荐
相关产品推荐

