нос, unittest.TestCase и метакласс: автоматически сгенерированные методы test_ * не обнаружены - PullRequest
12 голосов
/ 03 марта 2011

Это дополнительный вопрос для unittest и метакласса: автоматическая генерация 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

Однако, поскольку я на самом деле использую перенос , этот трюк, похоже, не согласен с ним. Вывод, который я получил:

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 Ответ

17 голосов
/ 03 марта 2011

Итак, после прохождения как через 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
...