2008-12-07 2 views
6

Это продолжение по сравнению с моим previous question.Как мне получить нос для обнаружения динамически генерируемых тестовых ящиков?

В предыдущем вопросе были изучены методы для реализации того, что было по существу тем же самым тестом по всему семейству функций, что обеспечило, что тестирование не прекратилось при первой неудавшейся функции.

Мое предпочтительное решение использовало метакласс для динамического вставки тестов в unittest.TestCase. К сожалению, нос не поднимает это, потому что нос статически сканирует для тестовых случаев.

Как получить нос, чтобы обнаружить и запустить такой TestCase? Пожалуйста, обратитесь к here за примером рассматриваемой TestCase.

+0

Вы пробовали мое решение? Он не основан на какой-либо магии, полученный пакет должен быть доступен для обнаружения. – muhuk 2008-12-07 15:50:19

ответ

7

Нос имеет функцию «тестового генератора» для таких вещей. Вы пишете функцию генератора, которая дает каждую функцию «тестового случая», которую вы хотите запустить, вместе с ее аргументами. После предыдущего примера, это может проверить каждую из функций в отдельном тесте:

import unittest 
import numpy 

from somewhere import the_functions 

def test_matrix_functions(): 
    for function in the_functions: 
     yield check_matrix_function, function 

def check_matrix_function(function) 
    matrix1 = numpy.ones((5,10)) 
    matrix2 = numpy.identity(5) 
    output = function(matrix1, matrix2) 
    assert matrix1.shape == output.shape, \ 
      "%s produces output of the wrong shape" % str(function) 
0

Вы могли бы попытаться создать классы TestCase с типом()

class UnderTest_MixIn(object): 

    def f1(self, i): 
     return i + 1 

    def f2(self, i): 
     return i + 2 

SomeDynamicTestcase = type(
    "SomeDynamicTestcase", 
    (UnderTest_MixIn, unittest.TestCase), 
    {"even_more_dynamic":"attributes .."} 
) 

# or even: 

name = 'SomeDynamicTestcase' 
globals()[name] = type(
    name, 
    (UnderTest_MixIn, unittest.TestCase), 
    {"even_more_dynamic":"attributes .."} 
) 

Это должен быть создан, когда нос пытается импортировать test_module поэтому он должен работать.

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

2

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

Жесткая часть состоит в том, что стандартные методы метакласса не устанавливают атрибут func_name правильно, что и ищет Нос, проверяя, являются ли методы вашего класса испытаниями.

Вот простой метакласс. Он просматривает функцию func dict и добавляет новый метод для каждого найденного метода, утверждая, что найденный метод имеет docstring. Этим новым синтетическим методам даются имена "test_%d" %i.

import new 
from inspect import isfunction, getdoc 

class Meta(type): 
    def __new__(cls, name, bases, dct): 

     newdct = dct.copy() 
     for i, (k, v) in enumerate(filter(lambda e: isfunction(e[1]), dct.items())): 
      def m(self, func): 
       assert getdoc(func) is not None 

      fname = 'test_%d' % i 
      newdct[fname] = new.function(m.func_code, globals(), fname, 
       (v,), m.func_closure) 

     return super(Meta, cls).__new__(cls, 'Test_'+name, bases, newdct) 

Теперь давайте создадим новый класс, который использует этот метакласса

class Foo(object): 
    __metaclass__ = Meta 

    def greeter(self): 
     "sdf" 
     print 'Hello World' 

    def greeter_no_docstring(self): 
     pass 

Во время выполнения Foo будет на самом деле будет называться Test_Foo и будет иметь greeter, greeter_no_docstring, test_1 и test_2 как его методы. Когда я бегу nosetests на этот файл, вот вывод:

$ nosetests -v test.py 
test.Test_Foo.test_0 ... FAIL 
test.Test_Foo.test_1 ... ok 

====================================================================== 
FAIL: test.Test_Foo.test_0 
---------------------------------------------------------------------- 
Traceback (most recent call last): 
    File "/Library/Frameworks/EPD64.framework/Versions/7.3/lib/python2.7/site-packages/nose/case.py", line 197, in runTest 
    self.test(*self.arg) 
    File "/Users/rmcgibbo/Desktop/test.py", line 10, in m 
    assert getdoc(func) is not None 
AssertionError 

---------------------------------------------------------------------- 
Ran 2 tests in 0.002s 

FAILED (failures=1) 

Это метаклассом не очень полезно, как есть, но если вы вместо того, чтобы использовать Meta не в качестве надлежащего метакласса, но как более функционального метакласса (т.е. берет класс в качестве аргумента и возвращает новый класс, тот, который переименован так, что нос найдет его), тогда оно - полезно. Я использовал этот подход для автоматического тестирования того, что docstrings придерживаются стандарта Numpy как часть набора тестов носа.

Кроме того, у меня было много проблем с получением надлежащего закрытия, работающего с новым.функция, поэтому в этом коде используется m(self, func), где func считается аргументом по умолчанию. Естественно было бы использовать закрытие над value, но это, похоже, не работает.

Смежные вопросы