Pytest - 如何断言函数是否调用了monkeypatched 方法

时间:2021-06-21 14:10:04

标签: python pytest monkeypatching

我有一个复杂的函数,可以调用许多其他 3rd 方方法。我一一把它们修补出来:

import ThirdParty as tp

def my_method():
  tp.func_3rd_party_1()
  ...
  tp.func_3rd_party_5()

  return "some_value"

在我的测试中:

import pytest

def test_my_method(monkeypatch):
    monkeypatch.setattr(ThirdParty, 'func_3rd_party_1', some_mock_1())
    ...
    monkeypatch.setattr(ThirdParty, 'func_3rd_party_5', some_mock_5())

    return_value = my_method()
    assert return value

这运行得很好,但这种形式的测试对我来说太含蓄了。我想明确指出,monkeypatched 方法确实被调用了。

为了记录,我的模拟方法没有使用任何内置的模拟库资源。它们只是重新定义的方法(智能存根)。

有什么办法可以断言吗?

1 个答案:

答案 0 :(得分:1)

因此专门提供了 pytest monkeypatching 固定装置,以便您可以更改一些全局属性,例如环境变量、第三方库中的内容等,从而为您的测试提供一些可控且简单的行为。

另一方面,Mock 对象旨在提供对对象的各种跟踪和检查。

这两者是相辅相成的:您使用补丁将某些第三方函数替换为 Mock 对象,然后执行您的代码,然后询问 Mock 对象是否确实使用正确的参数调用了正确的编号多次。

请注意,尽管 mock 模块是 unittest 的一部分,但它与 pytest 一起工作得非常好。

现在至于修补本身,这取决于您的个人喜好,并且在一定程度上取决于您想要修补的具体内容,是使用 unittest.mock.patch 更紧凑还是使用 pytest 的 monkeypatch 固定装置。

>
import pytest
from unittest.mock import Mock

def test_my_method(monkeypatch):
    # refer to the mock module documentation for more complex 
    # set ups, where the mock object _also_ exhibits some behavior.
    # as is, calling the function doesn't actually _do_ anything.
    some_mock_1 = Mock()
    ...
    some_mock_5 = Mock(return_value=66)

    monkeypatch.setattr(ThirdParty, 'func_3rd_party_1', some_mock_1)
    ...
    monkeypatch.setattr(ThirdParty, 'func_3rd_party_5', some_mock_5)

    some_mock_1.assert_called_once()
    some_mock_5.assert_called_with(42)
    ...

现在对此类测试进行说明:不要过火!它很容易导致所谓的脆弱测试:对您的代码稍加改动就会中断的测试。它可以使重构成为不可能的噩梦。

当您在以消息为中心的面向对象方法中使用这些类型的断言时,它们是最好的。如果被测类或方法的整个是以特定方式调用另一个对象的方法或类,则 Mock 离开。另一方面,如果对第三方函数的调用只是达到目的的一种手段,那么请在更高的级别进行测试并测试所需的行为