如何在测试中将一个类替换为另一个类并检查其方法是否被调用?

How to replace one class with another in a test and check that its method was called?

提问人:Boris Mirzakhanyan 提问时间:10/20/2023 最后编辑:frankfalseBoris Mirzakhanyan 更新时间:10/31/2023 访问量:65

问:

我想在测试中将一个类替换为另一个类,并检查其方法是否被调用。

我想做的一个示例是以下代码:

from unittest.mock import patch


class A:
    def some_method(self):
        print("A")


class B:
    def some_method(self):
        print("B")


def some_function():
    a = A()
    a.some_method()


def test_some_function():
    with patch("__main__.A", new=B) as mocked_a:
        some_function()
        assert mocked_a.some_method.called_once()

如何正确地做到这一点?

python 测试 模拟 pytest 包装器

评论


答:

1赞 Mohammad Shafqat Siddiqui 10/20/2023 #1

在您提供的代码中,您正在尝试使用 unittest.mock 库将类 A 修补为新的类 B,然后检查是否调用了 类 A。
但是,您的代码中存在一些问题,包括修补程序上下文管理器的不正确使用。在此更正后的代码中,我们使用补丁上下文管理器将类 A 替换为类 B,并模拟打印函数。
然后,我们检查是否调用了打印函数,将字符串传递给它,该字符串是类 B 的输出。 这是我的解决方案:
some_methodBsome_method

from unittest.mock import patch, MagicMock

class A:
    def some_method(self):
        print("A")

class B:
    def some_method(self):
        print("B")

def some_function():
    a = A()
    a.some_method()

def test_some_function():
    with patch("__main__.A", new=B):
        with patch("__main__.print") as mock_print:
            some_function()
            mock_print.assert_called_with("B")

if __name__ == "__main__":
    test_some_function()

评论

0赞 Boris Mirzakhanyan 10/20/2023
就我而言,我对打印功能不感兴趣。有没有办法检查some_method是否已被调用?
1赞 Mohammad Shafqat Siddiqui 10/20/2023
好的,代替“with patch(”main.print“) as mock_print:”通过这一行“with patch(”main.B.some_method“) 如mock_some_method:”并将此行 “mock_print.assert_called_with(”B“)” 更改为此行 “mock_some_method.assert_called_once()”
0赞 frankfalse 10/30/2023 #2

使用类 mock 的参数。模拟wraps

问题的一个可能解决方案可能是使用类的属性(请参阅本文档并搜索 )。因此,您的代码变为:wrapsmock.Mockwraps

from unittest.mock import patch, Mock    # <--- HERE I have added Mock in the import

class A:
    def some_method(self):
        print("A")

class B:
    def some_method(self):
        print("B")

def some_function():
    a = A()
    a.some_method()

def test_some_function():
    #with patch("__main__.A", new=B) as mocked_a:  # <--- HERE I have substitute
                                                   #      new=B with wraps=B()
    with patch("__main__.A") as mocked_a:
        mocked_a.return_value = Mock(wraps=B())
        some_function()
        assert mocked_a.some_method.called_once()

test_some_function()

执行我的代码的输出如下:

B

因此,这表明当它被调用时,执行了该方法,而不是类 A 的实例,已按照您在问题中的要求替换为类 B 的实例a.some_method()B.some_method()A.some_method()