我使用
unittest.mock.patch
和 wraps
来模拟函数,同时能够访问原始函数。例如:
from unittest import mock
def f(x, y):
return x * y
print(f(2, 3)) # output: 6
original_f = f
def m(x, y):
return original_f(x, y + 1)
with mock.patch('__main__.f', wraps=m) as mk:
print(f(2, 3)) # output: 8
但是,尝试模拟类方法的类似程序不起作用:
from unittest import mock
class A:
def __init__(self, x):
self.x = x
def f(self, y):
return self.x * y
a = A(2)
print(a.f(3)) # output: 6
original_f = A.f
def m(self, y):
return original_f(self, y + 1)
with mock.patch('__main__.A.f', wraps=m) as mk:
print(a.f(3)) # Exception
错误是:
Traceback (most recent call last):
File "a.py", line 18, in <module>
print(a.f(3))
^^^^^^
File "/usr/lib/python3.11/unittest/mock.py", line 1118, in __call__
return self._mock_call(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3.11/unittest/mock.py", line 1122, in _mock_call
return self._execute_mock_call(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3.11/unittest/mock.py", line 1192, in _execute_mock_call
return self._mock_wraps(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: m() missing 1 required positional argument: 'y'
看来mock包试图调用
m(self=3, y=<undefined>)
,所以发生了异常。
为什么
mock.patch
和 wraps
无法在类方法上工作?我应该如何修复我的程序?
编辑:
这是一个更复杂的工作示例,以证明这一点
a.f(3)
调用无法修改。run_test
) 无法访问测试者 (a
) 中的 test_target
。from unittest import mock
class A:
# This class cannot be changed
def __init__(self, x):
self.x = x
def f(self, y):
return self.x * y
def test_target():
# This function cannot be changed
a = A(2)
b = A(3)
return a.f(3), b.f(3)
def run_test():
print(test_target()) # output: (6, 9)
original_f = A.f
def m(self, y):
return original_f(self, y + 1)
with mock.patch('__main__.A.f', wraps=m) as mk:
#with mock.patch.object(A, 'f', wraps=m) as mk:
print(test_target()) # Exception
if __name__ == '__main__':
run_test()
f()
解决方案是更改对A类的方法f的调用。 此更改如下面的代码所示:
from unittest import mock
class A:
def __init__(self, x):
self.x = x
def f(self, y):
return self.x * y
a = A(2)
print(a.f(3)) # output: 6
original_f = A.f
def m(self, y):
return original_f(self, y + 1)
with mock.patch('__main__.A.f', wraps=m) as mk:
#print(a.f(3)) # Exception
print(a.f(a, 3)) # CHANGE THE CALL TO method f()
self
中删除
m()
或者如果您愿意 从函数中删除
self
属性 m()
:
from unittest import mock
class A:
def __init__(self, x):
self.x = x
def f(self, y):
return self.x * y
a = A(2)
print(a.f(3)) # output: 6
original_f = A.f
#def m(self, y):
# return original_f(self, y + 1)
def m(y): # <--- Remove the self attribute from m()
return original_f(a, y + 1) # <--- Pass a to original_f
with mock.patch('__main__.A.f', wraps=m) as mk:
print(a.f(3))