鼻子,unittest.TestCase和元类:未发现自动生成的test_*方法
这是 unittest 和元类:自动 test_* 方法生成<的后续问题/a>:
对于此(固定)unittest.TestCase 布局:
#!/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}_v4,6(self)
for suffix, arg in (('_false', False), ('_true', True)):
testable_name = 'test{0}{1}'.format(testname, suffix)
testable = lambda self, func=meth, arg=arg: func(self, arg)
attrs[testable_name] = testable
return type.__new__(cls, name, bases, attrs)
class TestCase(unittest.TestCase):
__metaclass__ = TestMaker
def test_normal(self):
print 'Hello from ' + self.id()
def _test_this(self, arg):
print '[{0}] this: {1}'.format(self.id(), str(arg))
def _test_that(self, arg):
print '[{0}] that: {1}'.format(self.id(), str(arg))
if __name__ == '__main__':
unittest.main()
这可以使用 stdlib
的框架。预期和实际输出:
C:\Users\santa4nt\Desktop>C:\Python27\python.exe test_meta.py
Hello from __main__.TestCase.test_normal
.[__main__.TestCase.test_that_false] that: False
.[__main__.TestCase.test_that_true] that: True
.[__main__.TestCase.test_this_false] this: False
.[__main__.TestCase.test_this_true] this: True
.
----------------------------------------------------------------------
Ran 5 tests in 0.015s
OK
但是,由于我实际上使用 nose,所以诡计似乎不太同意。我得到的输出是:
C:\Users\santa4nt\Desktop>C:\Python27\python.exe C:\Python27\Scripts\nosetests test_meta.py
.
----------------------------------------------------------------------
Ran 1 test in 0.000s
OK
简而言之,元类生成的 test_*
方法未注册 鼻子。任何人都可以阐明这一点吗?
谢谢,
This is a follow-up question for unittest and metaclass: automatic test_* method generation:
For this (fixed) unittest.TestCase layout:
#!/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}_v4,6(self)
for suffix, arg in (('_false', False), ('_true', True)):
testable_name = 'test{0}{1}'.format(testname, suffix)
testable = lambda self, func=meth, arg=arg: func(self, arg)
attrs[testable_name] = testable
return type.__new__(cls, name, bases, attrs)
class TestCase(unittest.TestCase):
__metaclass__ = TestMaker
def test_normal(self):
print 'Hello from ' + self.id()
def _test_this(self, arg):
print '[{0}] this: {1}'.format(self.id(), str(arg))
def _test_that(self, arg):
print '[{0}] that: {1}'.format(self.id(), str(arg))
if __name__ == '__main__':
unittest.main()
This works using stdlib
's framework. Expected and actual output:
C:\Users\santa4nt\Desktop>C:\Python27\python.exe test_meta.py
Hello from __main__.TestCase.test_normal
.[__main__.TestCase.test_that_false] that: False
.[__main__.TestCase.test_that_true] that: True
.[__main__.TestCase.test_this_false] this: False
.[__main__.TestCase.test_this_true] this: True
.
----------------------------------------------------------------------
Ran 5 tests in 0.015s
OK
However, since I am actually using nose, this trick seems to not agree with it. The output I got is:
C:\Users\santa4nt\Desktop>C:\Python27\python.exe C:\Python27\Scripts\nosetests test_meta.py
.
----------------------------------------------------------------------
Ran 1 test in 0.000s
OK
In short, the test_*
methods generated by the metaclass do not register with nose. Can anyone shed a light on this?
Thanks,
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
因此,在仔细研究了 stdlib 的
unittest
和鼻子的加载器和选择器源代码之后,结果发现,nose 重写了unittest.TestLoader.getTestCaseNames
以使用自己的选择器(带有插件点) )。现在,nose 的选择器会查找潜在方法的
method.__name__
来匹配某些正则表达式、黑白名单以及插件的决策。在我的例子中,动态生成的函数有其
testable.__name__ == ''
,不匹配鼻子的选择器标准。修复,
果然:
So, after sleuthing through both stdlib's
unittest
and nose's loader and selector source code, it turns out that nose overridesunittest.TestLoader.getTestCaseNames
to use its own selector (with plugin points).Now, nose's selector looks for a potential method's
method.__name__
to match certain regexes, black and white lists, and plugins' decisions.In my case, the dynamically generated functions have its
testable.__name__ == '<lambda>'
, matching none of nose's selector criteria.To fix,
And sure enough: