mock.patch 在 with 语句范围之外泄漏模拟对象

mock.patch leaks mocked object outside the scope of with statement

提问人:Aditya Bangard 提问时间:11/4/2023 更新时间:11/13/2023 访问量:43

问:

我在文件夹控制器下有以下三个python文件

  1. math.py
class Math:
    def __init__(self, a, b):
        self.a = a
        self.b = b

    def addition(self):
        return self.a + self.b
  1. calculation.py
from controller.math import Math


def perform_addition():
    math = Math(1, 2)
    return math.addition()
  1. test_sample.py
from unittest.mock import MagicMock, patch

def test_addition():


    mock_math = MagicMock()

    with patch('controller.math.Math', return_value=mock_math) as MockClass:
        instance = MockClass.return_value

        instance.addition.return_value = 100

        from controller.calculation import perform_addition
        output = perform_addition()

        print(output)  # prints 100

    post_patch_output = perform_addition()
    print(post_patch_output)  # prints 100 but expected 3

当我执行test_addition时,我希望返回 3,但它返回 100,即模拟输出。我很好奇我在这里错过了什么?post_patch_output

这里的 mock.patch 文档来看,它说的情况看起来不像这里的情况When the function/with statement exits the patch is undone.

python mocking python-unittest 补丁

评论


答:

0赞 frankfalse 11/9/2023 #1

对函数的更正test_addition

您必须修改文件,如下所示:test_sample.py

from unittest.mock import MagicMock, patch
from controller.calculation import perform_addition

def test_addition():

    mock_math = MagicMock()

    #with patch('controller.math.Math', return_value=mock_math) as MockClass:
    with patch('controller.calculation.Math', return_value=mock_math) as MockClass:
        instance = MockClass.return_value

        instance.addition.return_value = 100

        #from controller.calculation import perform_addition
        output = perform_addition()
        print(output)  # prints 100

    post_patch_output = perform_addition()
    print(post_patch_output)  # prints 100 but expected 3

test_addition()

这是执行的输出:test_addition()

100
3

如你所料。

代码中的错误

  • 您必须在文件内而不是在 .如果修补所有指向 Mock 对象的引用。因此,每次调用它时,都会使用 Mock 对象,而不是真正的类Mathcalculation.pymath.pycontroller.math.MathMathperform_addition()Math
  • 前面的修改就足够了,但我更喜欢在文件顶部执行导入,而不是在方法内部执行导入from controller.calculation import perform_additiontest_addition
  • 请记住,当您执行(即使在上下文管理器中)时,导入的名称(在您的情况下)在脚本中可用并引用对象。importperform_addition