unittest和metaclass:自动生成test_ *方法 [英] unittest and metaclass: automatic test_* method generation
问题描述
在为框架创建测试时,我开始注意到以下模式:
As I create tests for a framework, I start noticing the following pattern:
class SomeTestCase(unittest.TestCase):
def test_feat_true(self):
_test_feat(self, True)
def test_feat_false(self):
_test_feat(self, False)
def _test_feat(self, arg):
pass # test logic goes here
所以我想以编程方式为带有元类的这些类型的测试类创建test_feat_*
方法.换句话说,对于每个带有签名_test_{featname}(self, arg)
的私有方法,我希望创建两个带有签名test_{featname}_true(self)
和test_{featname}_false(self)
的顶级可发现方法.
So I want to programmatically create test_feat_*
methods for these type of test classes with a metaclass. In other words, for each private method with signature _test_{featname}(self, arg)
, I want two top-level, discoverable methods with the signatures test_{featname}_true(self)
and test_{featname}_false(self)
to be created.
我想出了类似的东西:
#!/usr/bin/env python
import unittest
class TestMaker(type):
def __new__(cls, name, bases, attrs):
callables = dict([
(meth_name, meth) for (meth_name, meth) in attrs.items() if
meth_name.startswith('_test')
])
for meth_name, meth in callables.items():
assert callable(meth)
_, _, testname = meth_name.partition('_test')
# inject methods: test{testname}_{[false,true]}(self)
for suffix, arg in (('false', False), ('true', True)):
testable_name = 'test{0}{1}'.format(testname, suffix)
attrs[testable_name] = lambda self: meth(self, arg)
return type.__new__(cls, name, bases, attrs)
class TestCase(unittest.TestCase):
__metaclass__ = TestMaker
def _test_this(self, arg):
print 'this: ' + str(arg)
def _test_that(self, arg):
print 'that: ' + str(arg)
if __name__ == '__main__':
unittest.main()
我期望一些输出,例如:
I expect some output like:
this: False
this: True
that: False
that: True
但是我得到的是:
$ ./test_meta.py
that: True
.that: True
.that: True
.that: True
.
----------------------------------------------------------------------
Ran 4 tests in 0.000s
OK
似乎我缺少一些关闭规则.我该如何解决?有更好的方法吗?
It looks like there are some closure rules that I am missing. How do I get around this? Is there a better approach?
谢谢
edit :已修复.参见:摘录.
推荐答案
实际上,这是一个关闭问题:
Indeed, it is a closure issue:
更改
attrs[testable_name] = lambda self: meth(self, arg)
到
attrs[testable_name] = lambda self,meth=meth,arg=arg: meth(self, arg)
通过使用默认值,lambda内部的arg
绑定到在每次循环迭代期间设置的默认值arg
.如果没有默认值,在循环的所有迭代完成后,arg
将采用最后的值arg
. (meth
也是如此).
By using a default value, arg
inside the lambda is bound to the default value arg
set during each iteration of the loop. Without the default value, arg
takes on the last value of arg
after all the iterations of the loop have completed. (And the same goes for meth
).
这篇关于unittest和metaclass:自动生成test_ *方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!