带有参数的测试装饰器总是被执行
Posted
技术标签:
【中文标题】带有参数的测试装饰器总是被执行【英文标题】:Test decorators with arguments are always executed 【发布时间】:2015-10-16 06:36:17 【问题描述】:我想要实现的是将某些测试所需的设置代码放入装饰器函数中。我故意避免 setUp
和 tearDown
方法,因为它们由测试用例中的所有测试共享,这不是我想要的。这更多的是个人喜好和学习兴趣的问题,而不是直接的解决方案。
简化版代码:
# some import lines
from some.package import interceptor
class TestWhatever(unittest.TestCase):
def test_simple_thing(self):
# simple stuff
def test_another_simple_thing(self):
# more simple stuff
@interceptor(arg1, arg2)
def test_with_some_preparation_needed(self):
# hey! Really cool stuff in here
print('This will be executed with every test')
@interceptor(arg1, arg2, namedarg1='foo', namedarg2='bar')
def test_with_preparation_also(self):
# the first decorator is executed
# sure I'm not following Python's Zen
装饰器功能:
from wsgi_intercept import requests_intercept
from wsgi_intercept import add_wsgi_intercept
def interceptor(cityname, response, host='localhost', port=8000):
requests_intercept.install()
add_wsgi_intercept(host, port,
lambda: create_webservice(cityname, response))
def decorator(test):
def runtest(self):
test(self)
requests_intercept.uninstall()
return runtest
return decorator
def create_webservice(cityname, response):
def app(environ, start_response):
# a simple WSGI app
return app
每个装饰器都是一个带参数的函数调用,因为我需要参数化设置。调用返回测试的真实装饰器。问题是它们就像放置在函数定义之间的任何其他语句一样,因此它们会被执行。
像我这样用参数测试装饰器的想法可行吗?也许有了数据提供者就可以了。
【问题讨论】:
函数在模块加载时被修饰。所以,是的,mydecorator(arg1, arg2)
和 mydecorator(arg1, arg2, namedarg1='foo', namedarg2='bar')
表达式总是被执行。向我们展示您的实际装饰器,以便我们能够帮助您找出仅在执行 test_with_some_preparation_needed
和 test_with_preparation_also
方法时才执行的代码。
print()
调用是类主体的一部分,所以是的,它也会被执行。我实际上不确定您的问题是什么; print()
函数与这里的装饰器无关。
print()
行只是我所说的“就像放置在函数定义之间的任何其他语句一样,因此它们被执行”时的一个示例。
我尝试将装饰器函数放在测试类内部、外部和导入的模块中,结果是一样的。我知道我可以在需要时通过在测试的开始和结束时调用一些实用程序函数来解决这个问题,但是装饰器方法对我来说似乎更干净。
我强烈建议放弃 unittest 并改用 py.test,因为它有 fixtures。如果您在重新打开时 ping 我,我可以将其扩展为答案。
【参考方案1】:
将您希望在每个测试中执行的所有内容移动到runtest
包装器中。 interceptor()
装饰器工厂和decorator
本身都会在创建TestWhatever
类对象时执行:
def interceptor(cityname, response, host='localhost', port=8000):
def decorator(test):
def runtest(self):
requests_intercept.install()
add_wsgi_intercept(
host, port,
lambda: create_webservice(cityname, response))
test(self)
requests_intercept.uninstall()
return runtest
return decorator
请注意,正常模式仍然使用setUp
和tearDown
,并且仅将那些需要特定设置的测试放在该类中。您可以随时添加更多 TestCase
类,而无需为其他测试设置该设置:
class TestWhateverWithSetup(unittest.TestCase):
def setUp(self):
requests_intercept.install()
add_wsgi_intercept(
host, port,
lambda: create_webservice(cityname, response))
def tearDown(self):
requests_intercept.uninstall()
def test_with_some_preparation_needed(self):
# hey! Really cool stuff in here
def test_with_preparation_also(self):
# the first decorator is executed
# sure I'm not following Python's Zen
class TestWhateverWithoutSetup(unittest.TestCase):
def test_simple_thing(self):
# simple stuff
def test_another_simple_thing(self):
# more simple stuff
【讨论】:
感谢@MartijnPieters。整洁的。我会按照你的建议去做。无论如何,了解py.test
很有趣,我将进一步探索其他选择。以上是关于带有参数的测试装饰器总是被执行的主要内容,如果未能解决你的问题,请参考以下文章