2016-04-03 27 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

相关问题