2016-11-29 1 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) 

Okだから、デコレータregister_processorは期待通りに動作します。テストは失敗しますが、内部クラスの名前をカスタマイズ可能にしたいので、代わりにデコレータファクトリの実装に行きました。unittestメソッドのデコレータファクトリ

私は、次の取得register_processor2で飾られたテストを実行しているときのものです:バインドされた方法は、ここでTestPaymentMethodEndpointsのインスタンスfuncではなく、なぜ

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

これは@wraps(func)から、私の質問はされます?

デコレータ@wrapsを削除した場合、テストが実行され、が渡されます。 func_wrappertest_*で始まらず、発見されてもテストが失敗するため、テストが検出されないことが期待されます。

何が起こっているかについての洞察とこれをどうやってやっていくのですか?

EDIT

だから私は、デコレータの工場は、あなたはまだそれを呼び出すとき()を配置する必要があり、デフォルト値を持つ引数がある場合でも、それを考え出しました。

しかし、最初にテストが合格/発見された場合に何が起こったのかについての説明を聞くのが大好きです。

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

私はそれについて考えるようになりました:D、あなたは毎日何か新しいことを学びます!

答えて

1

testという名前の関数でラップされたテストケースを、どのようにしてunittestモジュールが見つけることができますか? unittestはそれがそれらを見つけるために属性名テストケースクラスのを使用して、実行するための方法を見つけることが名前の関数のを使用しないため

それに対する答えがあります。

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

が、その属性の値がラッピング機能wrap_with_fixtureであること:あなたがdirからの出力は、名前test_somethingが含まれていることがわかります

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() 

したがって、次のコードを実行してみてください:

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

デコレータ工場の後にブラケットを入れない場合、いつ、いつか混乱する可能性はありますか?実際にデコレータ関数であるテストケースを作成したかもしれません。デコレータファクトリは、 'test_method'で呼び出されます。' 'デコレータファクトリは、' 'test_method''で呼び出されます。テストケースとして使用されるデコレータを返しますが、テストをラップする新しい関数を作成し、実際にはテストを実行しないので、渡すように見えます。 – daphtdazz

+0

これは、テストを実行しているときに、アサーションエラーをキャッチし、テスト関数__name__に基づいて何らかのdictに失敗したテストを格納します。これはdictには含まれないため、無視されます。とにかく、私は本質的にそれの要点を持って、ありがとう。 – Krotz