我正在尝试围绕py.test建立一个不错的基础
我们的一些测试需要某些测试数据才能工作。
今天我们只是将模拟对象指定为函数参数并在生成器中进行设置,这显然是不可取的。
以下是今天的展示方式示例:
def test_something(self, some_data):
# some_data is unused in the test
我想做这样的事情:
@uses_some_data
def test_something(self):
# The data is loaded when the test is run
虽然我还没弄清楚如何正确地做到这一点。
我不能使用类设置,因为我希望数据在整个会话中保持不变,而不是在每个测试类上设置/拆除。
我的第一个想法是仍然使用funcargs但是我们让装饰器为函数请求funcarg,而不是让测试有funcarg,基本上隐藏了丑陋。
这个问题是我需要一个py.test对象来请求一个funcarg 有什么方法可以得到这样的对象,或者这是一起错误的方法吗?
如果收集的测试都不需要数据,则不需要加载数据,这将是一个非常好的奖励,这是使用装饰器看到的缺点,因为无论是否运行测试,它们总是运行不
答案 0 :(得分:1)
这是可以按原样运作的东西,如果没有,希望能指出你正确的方向。
class TestData(object):
def __getattr__(self, name):
if name not in ('data1', 'data2', 'data3'):
raise AttributeError("TestData has no %s" % name)
if name == 'data1':
result = self._generate_data('data1')
setattr(self.__class__, name, result)
elif name == 'data2':
result = self._generate_data('data2')
setattr(self.__class__, name, result)
elif name == 'data3':
result = self._generate_data('data3')
setattr(self.__class__, name, result)
return result
def _generate_data(self, data_name):
return data_name * int(data_name[-1])
TestData类使用__getattr__
方法根据需要生成数据,并将生成的日期保存回类(而不是实例!),数据保留以备将来使用
class uses_some_data(object):
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
global test_data
test_data = TestData()
return self.func(*args, **kwargs)
一个简单的装饰器,用于设置test_data
的全局名称绑定。实际上,这个版本的装饰器非常简单,可以很容易地用test_data = TestData()
的模块级名称绑定替换。
@uses_some_data
def testing_test():
print(test_data.data2)
测试功能。
如果您不喜欢test_data
的全局级别,您可以更好地使用装饰器并将test_data
分配给函数本身:
class uses_some_data(object):
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
self.func.test_data = TestData()
return self.func(*args, **kwargs)
在这种情况下,请确保您的测试功能自行引用
@uses_some_data
def testing_test():
print(testing_test.test_data.data2)
答案 1 :(得分:1)
在玩了一些后,我发现这有效:
def pytest_funcarg__some_data(request):
def create():
# Load the test data here
print 'Test data loaded'
return request.cached_setup(
setup=create,
scope='session',
extrakey='some_data'
)
def uses_some_data(func):
# The funcarg is actually requested here
def wrapper(self, some_data):
return func
return wrapper
class TestSomething(object):
@uses_some_data
def test_something(self):
# "Some data" is now available
pass