2016-04-03 54 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: 

那麼實例方法「富」不再嘲笑。

有沒有人知道這是爲什麼?

我也遇到過一些更復雜的代碼的類似問題,其中生產代碼位於my_package/src/production_file.py中,而測試位於my_package/tests/test_file.py中。 Python對路徑不產生任何錯誤,路徑是正確的,但仍然模擬不起作用。

回答

2

如果您正在運行test.py__main__那麼它是不是test.MyClass這將是__main__.MyClass,或者在這兩種情況下__name__+".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'> 

其指示:(至少一個用於測試的那一個)

  1. 有沒有施加到MyClass修補
  2. 需要被修補的類的名稱是__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: 
      ... 

在這種情況下production_file.MyClass正在修補和MyClass正在從進口production_file所以正確的類被修補,但仍輸出:

<class 'production_file.MyClass'> 

這是因爲類直接導入到本地命名空間,因此當補丁應用到production_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'> 

如果這是你只需要導入模塊的情況下,而不是直接類。然後一旦應用補丁,您將從文件中使用它:

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

有趣......但爲什麼不產生錯誤,如果路徑錯誤? – Feoggou

+0

因爲沒有任何問題,它只是修補錯誤的地方,如果你有一個'test.py'文件,並且你在其中導入測試,那麼你最終會得到兩個版本的相同文件,這些文件都是用不同的名字加載的。如果你添加了'if __name__ =='__main__「:從測試導入MyClass ...'等它會按預期工作,因爲它正在修補你正在使用的測試類。 –

+0

我還有一個更復雜的情況,我有my_package/src/my_file.py和my_package/tests/test.py。在這種情況下,我的一個測試使用了補丁(「src.my_file.MyClass」),但仍然無法正常工作。有沒有辦法讓我調試/記錄測試實際上正在修補的內容? – Feoggou

相關問題