2016-04-03 7 views
1

プロダクションファイル(production_file.py)のために動作しませんです。のpython3のモックは、すべてのパス

class MyError(Exception): 
    pass 

class MyClass: 
    def __init__(self): 
     self.value = None 

    def set_value(self, value): 
     self.value = value 

    def foo(self): 
     raise RuntimeError("error!") 


class Caller: 
    def bar(self, smth): 
     obj = MyClass() 
     obj.set_value(smth) 

     try: 
      obj.foo() 
     except MyError: 
      pass 

     obj.set_value("str2") 
     obj.foo() 

テストファイル(test.py):

import unittest 

from unittest.mock import patch 
from unittest.mock import call 
from production_file import MyClass, Caller 

class MyTest(unittest.TestCase): 
    def test_caller(self): 
     with patch('production_file.MyClass', autospec=MyClass) as MyClassMock: 
      my_class_mock_obj = MyClassMock.return_value 
      my_class_mock_obj.foo.side_effect = [MyError("msg"), "text"] 

      caller = Caller() 
      caller.bar("str1") 

      calls = [call("str1"), call("str2")] 

      my_class_mock_obj.set_value.assert_has_calls(calls) 

if __name__ == '__main__': 
    unittest.main() 

これ以上の作品。しかし、私はテストファイルに生産クラス(MyError、MyClassの、発信者)を移動し、アップデートパッチの場合:

with patch('test.MyClass', autospec=MyClass) as MyClassMock: 

は、そのインスタンスメソッド「foo」がもはや嘲笑されます。

それは誰でも知っていますか?

私はまた、テストがmy_package/tests/test_file.pyにある間に、生産コードがmy_package/src/production_file.pyにある、より複雑なコードで同様の問題を経験しました。 Pythonはパスに対してエラーを起こさず、パスは正しいですが、モックは機能しません。

答えて

2

あなたは__main__としてtest.pyを実行している場合、それはそれは__main__.MyClass、または__name__+".MyClass"両方のケースになりますtest.MyClassではありません。

私はクラスが使用されていることを決定することができましたし、パッチを適用したクラスは、print文を追加することで異なっていた:

class Caller: 
    def bar(self, smth): 
     print(MyClass) #lets see what we are actually making an instance of... 
     obj = MyClass() 
     ... 

パッチが、これはあなたがこのようなものを見ることが使用しているクラスに適用された場合:

<MagicMock name='MyClass' spec='MyClass' id='4387629656'> 

しかし、中クラスはtest.pyに移動したときに表示されます何かのように:

<class '__main__.MyClass'> 
(。テストのために使用されている少なくとも一つの) MyClassに適用されていないパッチの適用はありませんでした
  1. パッチを適用する必要のあるクラスの名前は__main__.MyClass
です:示し

from production_file import MyClass 

class MyError(Exception): 
    pass 


class Caller: 
    def bar(self, smth): 
     print(MyClass) 
     obj = MyClass() 
     ... 

class MyTest(unittest.TestCase): 
    def test_caller(self): 
     with patch('production_file.MyClass', autospec=MyClass) as MyClassMock: 
      ... 
:あなたの「もっと...複雑な状況は、」なぜなら、このような設定で動作していない可能性が極めて高いですが

<class 'production_file.MyClass'> 

クラスが直接ので、ローカル名前空間にインポートされたので、これは次のとおりですので、正しいクラスがパッチが適用されているが、まだ出力されている。この場合production_file.MyClass

は、パッチが適用されているとMyClassproduction_fileから輸入されていますこれはあなただけのモジュールをインポートする必要がある場合、直接ではなくクラスである場合

... 
def bar(self, smth): 
    print(MyClass) 
    from production_file import MyClass as pf_MyClass 
    print(pf_MyClass) 
... 


#output: 
<class 'production_file.MyClass'> 
<MagicMock name='MyClass' spec='MyClass' id='4387847136'> 

:パッチがローカル名前空間はまだ影響を受けませんproduction_fileに適用した場合、我々は、パッチが実際に適用されたことを確認することができます。パッチが適用されると、ファイルからすぐに使用されます。

import production_file 

... 
class Caller: 
    def bar(self, smth): 
     print(production_file.MyClass) 
     obj = production_file.MyClass() 
     ... 

class MyTest(unittest.TestCase): 
    def test_caller(self): 
     with patch('production_file.MyClass', autospec=MyClass) as MyClassMock: 
      ... 
+0

面白いですが...なぜ、パスが間違っていても、Pythonはエラーになりませんか? – Feoggou

+0

何も間違っているので、間違った場所にパッチを当てているだけです。ファイル 'test.py'を持っていれば、' import test'で別の名前でロードされた同じファイルの2つのバージョンになります。 'if __name__ ==" __main__ ":test import MyClass ...'などを追加した場合、テスト用に使用しているクラスにパッチを当てているので、期待どおりに動作します。 –

+0

私は、もっと複雑な状況にも問題があります。ここでは、my_package/src/my_file.pyとmy_package/tests/test.pyがあります。この場合、私のテストではpatch( "src.my_file.MyClass")を使用していますが、モックは機能しません。テストが実際にパッチを適用していることをデバッグ/ログに記録する方法はありますか? – Feoggou

関連する問題