[英]python mock: replacing a class method
Consider the following code (not a very good design, but that's the point): 考虑以下代码(这不是一个很好的设计,但这就是重点):
class A(object):
def __init__(self,filepath):
self._access_file_system(filepath)
def get(self):
return self._result_dict
class B(object):
def __init__(self,filepath1,filepath2):
self._filepath1 = filepath1
self._filepath2 = filepath2
def foo(self):
a1 = A(self._filepath1).get()
a2 = A(self._filepath2).get()
return a1['result']==a2['result']
Now, if I want to test B.foo()
, I need to mock A
(as it accesses the file-system inside the constructor). 现在,如果我想测试
B.foo()
,我需要模拟A
(因为它访问了构造函数中的文件系统)。
To write a test that will make sure B.foo()
returns False
in case a1.get()
and a2.get()
provide different values, I also need to mock B.get()
. 要编写一个测试,将确保
B.foo()
返回False
的情况下, a1.get()
和a2.get()
提供不同的价值观,我还需要模拟B.get()
So, the test function should probably look like the following: 因此,测试功能可能应如下所示:
import mock
mock_get = mock.MagicMock(side_effect=[{'result': 0}, {'result': 1}])
@mock.patch('__main__.A')
def test_foo(MockA):
b = B('/file1','/file2')
res = b.foo()
assert res
MockA.assert_any_call('/file1')
MockA.assert_any_call('/file2')
#Doesn't work -
#the assignment doesn't propagate into the objects instantiated inside foo()
#A.get = mock_get
#The assigned method propagates into the class definition,
#so it works - BUT WHY?!
a = A(None)
a.get = mock_get
b = B('/file1', '/file2')
res = b.foo()
assert not res
Now, the strange point - as may be seen from the comments inside the code, if we assign mock_get
to the class, it won't propagate, but if we create an instance and assign to it, it propagates to other instances of the class. 现在,奇怪的一点-从代码内的注释中可以看出,如果我们将
mock_get
分配给该类,它将不会传播,但是如果我们创建一个实例并将其分配给它,则它会传播给该类的其他实例。
I suppose this behavior is related to internal mechanisms of mock
, so it's important for me to understand it, to make proper usage of this library with all it's rich functionality. 我想这种行为与
mock
内部机制有关,因此对我来说很重要的一点是要理解它,并充分利用此库的所有丰富功能。
So, does anyone has a clue? 那么,有人知道吗?
On the first case I can not see anywhere that you are patching the get
method. 在第一种情况下,我看不到您正在修补
get
方法的任何地方。 You should assign the mock value to the get
method of A
before B
is called. 在调用
B
之前,应将模拟值分配给A
的get
方法。 For instance why does the following test fail?: 例如,为什么以下测试失败?:
import mock
mock_get = mock.MagicMock(side_effect=[{'result': 0}, {'result': 1}])
@mock.patch('__main__.A')
def test_foo(MockA):
MockA.get = mock_get
b = B('/file1','/file2')
res = b.foo()
assert not res
MockA.assert_any_call('/file1')
MockA.assert_any_call('/file2')
The reason for the previous behaviour is that we are forgetting to patch the return value of the object (A), in this case MockA
, instead of the object itself ( MockA
). 先前行为的原因是我们忘记修补对象(A)的返回值,在本例中为
MockA
,而不是对象本身( MockA
)。 The A
object is the result of instantiating the A
class and you should access the method throgh the return_value
of the A
class. A
对象是实例化A
类的结果,您应该通过A
类的return_value
访问方法。 In your example it would be something similar to this: 在您的示例中,将类似于以下内容:
import mock
mock_get = mock.MagicMock(side_effect=[{'result': 0}, {'result': 1}])
@mock.patch('__main__.A')
def test_foo(MockA):
MockA.return_value.get = mock_get
b = B('/file1','/file2')
res = b.foo()
assert res
MockA.assert_any_call('/file1')
MockA.assert_any_call('/file2')
You can check some of the following posts for more info on common python unit testing pitfalls: 您可以查看以下一些帖子,以获取有关常见python单元测试陷阱的更多信息:
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.