如何在类方法上使用mock.patch和wrap?

问题描述 投票:0回答:1

我使用

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
无法在类方法上工作?我应该如何修复我的程序?

编辑:

这是一个更复杂的工作示例,以证明这一点

  1. a.f(3)
    调用无法修改。
  2. 测试者 (
    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()
python mocking
1个回答
0
投票

更改对方法的调用
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))

© www.soinside.com 2019 - 2024. All rights reserved.