2016-11-29 63 views
1
def register_processor2(processor_name='SomeProcessor'): 
    def decorator(func): 
     class SomeProcessor(GenericPaymentProcessor, TriggeredProcessorMixin): 
      name = processor_name 
      transaction_class = Transaction 

      @staticmethod 
      def setup(data=None): 
       pass 

     @wraps(func) 
     def func_wrapper(*args, **kwargs): 
      PaymentProcessorManager.register(SomeProcessor) 
      result = func(*args, **kwargs) 
      PaymentProcessorManager.unregister(SomeProcessor) 
      return result 

     return func_wrapper 
    return decorator 


def register_processor(func): 
    class SomeProcessor(GenericPaymentProcessor, TriggeredProcessorMixin): 
     name = 'SomeProcessor' 
     transaction_class = Transaction 

     @staticmethod 
     def setup(data=None): 
      pass 

    @wraps(func) 
    def func_wrapper(*args, **kwargs): 
     PaymentProcessorManager.register(SomeProcessor) 
     result = func(*args, **kwargs) 
     PaymentProcessorManager.unregister(SomeProcessor) 
     return result 

    return func_wrapper 


class TestPaymentMethodEndpoints(APITestCase): 
    @register_processor 
    def test_put_detail_cannot_change_processor(self): 
     self.assertEqual(True, False) 

好吧,所以装饰工register_processor按预期工作。测试失败,但我想让内部类的名称可定制,所以我改为装饰工厂实现。单元测试方法的装饰工厂

的事情是运行测试饰register_processor2时,我得到如下:

AttributeError: 'TestPaymentMethodEndpoints' object has no attribute '__name__'

这是从@wraps(func),我的问题是,为什么是func这里的TestPaymentMethodEndpoints一个实例,而不是绑定的方法?

此外,如果我删除@wraps修饰器,然后测试运行并通过。 我希望测试不会被发现,因为func_wrapper不以test_*开头,即使发现它也会失败。

任何有关正在发生的事情以及我将如何去做这件事的见解?

编辑

所以我想通了,即使装饰工厂有有你仍然需要调用它时放置()默认值的参数。

但是仍然希望听到关于在测试通过/发现的情况下发生了什么的解释。

class TestPaymentMethodEndpoints(APITestCase): 
    @register_processor() 
    def test_put_detail_cannot_change_processor(self): 
     self.assertEqual(True, False) 

现在我觉得有意义了:D,天哪,你每天都会学到新的东西!

回答

1

我想你现在问“unittest模块怎么能找到已包装在名称不能启动test的函数中的测试用例?

这个问题的答案是因为unittest不使用的功能的找到方法来运行,它采用了属性名的测试用例类的找到他们。

因此,尝试运行下面的代码:

from unittest import TestCase 

def apply_fixture(func): 

    def wrap_with_fixture(self): 
     print('setting up fixture...') 
     try: 
      func(self) 
     finally: 
      print('tearing down fixture') 

    return wrap_with_fixture 


class MyTestCase(TestCase): 

    @apply_fixture 
    def test_something(self): 
     print('run test') 


print('Attributes of MyTestCase: %s' % dir(MyTestCase)) 
print('test_something method: %s' % MyTestCase.test_something) 

mtc = MyTestCase() 
mtc.test_something() 

你会看到,从dir输出包含名称test_something

Attributes of MyTestCase: ['__call__', ...lots of things..., 'test_something'] 

但该属性的值是包装功能部件wrap_with_fixture

test_something method: <function apply_fixture.<locals>.wrap_with_fixture at 0x10d90aea0> 

当你考虑到当你创建一个函数的时候,你同时使用提供的名字和一个局部变量来创建一个函数,并且这个装饰器的语法只是语法糖,那么这是有道理的,所以下面是一个同样有效,尽管创建你的测试用例类的方法更长:

class MyTestCase(TestCase): 

    def test_something(self): 
     print('run test') 
    # Overwrite existing 'local' (or 'class' variable in this context) 
    # with a new value. We haven't deleted the test_something function 
    # which still exists but now is owned by the function we've created. 
    test_something = apply_fixture(test_something) 
+0

好吧,这是有道理的,但为什么测试通过首先:D。我的意思是它不应该。 – Krotz

+1

您是否有可能在装修工厂之后和何时不把括号放在后面而感到困惑?您可能已经创建了一个实际上只是装饰器功能的测试用例,例如'def decorator_factory(* args,** kwargs):... return decorator',然后是'@decorator_factory def test_method(self):self.assertEqual(True,False)',因此这里的装饰器工厂用'test_method'调用并返回一个用作测试用例的装饰器,但它只是创建一个包装测试的新函数,并且实际上并不运行测试,所以看起来会通过。 – daphtdazz

+0

无论是运行测试还是运行测试时,它都会捕获断言错误,并将失败的测试存储在基于测试函数__name__的字典中,该测试函数__name__不在字典中,因此它忽略它。无论如何,我从本质上得到了它的要义,谢谢。 – Krotz