2016-08-10 12 views
3

私のアプリケーションの単体テストでは、常に@mock.patch@patch.objectデコレータを使用していました。しかし、デコレータを使用したときのユニットテストでは、 'TypeError:staticmethodオブジェクトはイテレータではありません'というエラーが表示されます。Pythonで '@ patch.object'と 'with patch.object'を使用する違いは何ですか?

同じコードで、mock.patch.objectまたはmock.patch.objectを使用すると、すべて正常に機能します。

例えば、私のテストクラスで、私はこの方法を持っている:staticmethodオブジェクト:

@staticmethod 
def my_mock(): 
    ...do something 

私は、次のユニットテスト

@mock.patch('mypackage.mymodule.my_method', side_effect=my_mock) 
def test_something(self, my_method_mocked): 
    ...test something 

をしようとすると、私ははTypeError「前に述べたエラーメッセージが表示されます。イテレータではありません '

しかし、私はこのよう

def test_something(self): 
    with patch.object(mymodule, "my_method") as mocked_method: 
     mocked_method.side_effect = self.my_mock 
     ...test something 

をしようとすると、その後、すべてが完璧に動作します。

モックとユニットテストに関するPythonのドキュメントを読んだことがありますが、この動作の説明は見つかりませんでした。

デコレータパターンのパターンがの場合の違いは何ですか?私はこれについてもっと知ることができる場所?

だけで、この私のコードの構造がより明確にするために:

class TestClass(unittest.TestCase): 

    @staticmethod 
    def my_mock(): 
    ...mock 
     return service 

    # doesn't work 
    @mock.patch('mypackage.mymodule.my_method', side_effect=my_mock) 
    def test_something(self, my_method_mocked): 
     ...test something 

    # work 
    def test_something(self): 
    with patch.object(mymodule, "my_method") as mocked_method: 
     mocked_method.side_effect = self.my_mock 
     ...test something 

私はTestClass.my_mockを行うことができない理由です。私がしたら、私は参照エラーを取得します。

答えて

1

を追加する必要があると思います。違いは、patchを呼び出す方法ではなく、それぞれの場合にside_effect属性に割り当てる値です。

class A(object): 
    @staticmethod 
    def my_mock(): 
     pass 

    print type(my_mock) # As in your decorator case 

# As in your context manager case 
print type(A.my_mock) 
print type(A().my_mock) 

このコードを実行する場合は、メソッド自体への参照を持っているので、あなたは、クラス宣言の出力<type 'staticmethod'>内部そのprint文が表示されます。

他の2つのprintステートメント出力<type 'function'>がありませんにはメソッドがあります。メソッドの__get__メソッドの戻り値への参照があります。 2つの呼び出しが記述子がメソッド(静的、クラス、およびインスタンス)の3種類を実装するために使用される方法のより完全な議論についてはhttps://docs.python.org/2/howto/descriptor.html参照

print type(A.__dict__['my_mock'].__get__(A)) 
print type(A.__dict__['my_mock'].__get__(A())) 

と等価です。


patchが、それは、戻り値の反復可能を必要とするside_effect引数の値として呼び出し可能な、および失敗、と予想しているため、実際の誤差は約来ます。 staticmethodオブジェクトは呼び出しも反復もできません。 (試してみてください:A.__dict__['my_mock']()

関数を確実に取得するには、クラスを通してメソッドにアクセスする必要があります。

class Foo(object): 
    @staticmethod 
    def my_mock(): 
     "whatever it does" 

@mock.patch('mypackage.mymodule.my_method', side_effect=Foo.my_mock) 
def test_something(self, my_method_mocked): 
    ...test something 
+0

しかし、私は '@classmethod'のときにこのFoo.my_mockのようなメソッドしか参照できません。 '@ staticmethod'は動作しません。 –

+0

'Foo.my_mock'は静的メソッドにアクセスする必要があります。静的メソッドとクラスメソッドの唯一の違いは、静的メソッドがそのクラスへの参照を引数として取得しないことです。 – chepner

+0

静的メソッドとして 'my_mock'を使って' Foo.my_mock'と言ったような使い方をしようとすると、私はそれをすることができないというエラーが出ます。しかし、クラスメソッドとして 'my_mock'を宣言すると、私はそれを使うことができます。 –

0

私はあなただけあなたがPythonの記述プロトコルの効果を見ているクラス名に

class mymodule: 
    @staticmethod 
    def my_mock(): 
     ...do something 
... 

@mock.patch('mypackage.mymodule.my_method', side_effect=mymodule.my_mock) 
def test_something(self, my_method_mocked): 
    ...test something 
関連する問題