Нос, unittest.TestCase и метакласс: автогенерация test_ * методы не обнаружены
Это следующий вопрос для unittest и metaclass: автоматическое создание метода test_ *:
Для этого (фиксированного) макета 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_*
, сгенерированные метаклассом, не регистрируются nose. Может ли кто-нибудь пролить свет на это?
Спасибо,
Ответы
Ответ 1
Таким образом, после того, как он проходит через оба stdlib unittest
и носовой загрузчик и исходный код селектора, оказывается, что нос переопределяет unittest.TestLoader.getTestCaseNames
, чтобы использовать свой собственный селектор (с плагинами).
Теперь селектор носа ищет потенциальный метод method.__name__
для соответствия определенным регулярным выражениям, черно-белым спискам и решениям плагинов.
В моем случае динамически сгенерированные функции имеют testable.__name__ == '<lambda>'
, не соответствующие ни одному из критериев выбора носа.
Чтобы исправить,
# 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, arg=arg: meth(self, arg)
testable.__name__ = testable_name # XXX: the fix
attrs[testable_name] = testable
И конечно:
(sandbox-2.7)bash-3.2$ nosetests -vv
test_normal (test_testgen.TestCase) ... ok
test_that_false (test_testgen.TestCase) ... ok
test_that_true (test_testgen.TestCase) ... ok
test_this_false (test_testgen.TestCase) ... ok
test_this_true (test_testgen.TestCase) ... ok
----------------------------------------------------------------------
Ran 5 tests in 0.005s
OK