辅助函数中的修补未应用于实例

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

我正在使用

unittest.mock.patch
创建一个测试,看起来像这样:

class TestService:
  def test_patched(self):
    service = Service()
    with patch.object(service, "_send_to_third_party") as patch_send:
      with patch.object(service, "_notify_listeners") as patch_notify:
        service.do_something()
        patch_send.assert_called_once()
        patch_notify.assert_called_once()

所有这些都工作正常,但我想将这些补丁放入一个方法中,以便我可以在一堆测试中重用它。像这样:

class TestService:
  def _patched_service(self):
    service = Service()
    with patch.object(service, "_send_to_third_party") as patch_send:
      with patch.object(service, "_notify_listeners") as patch_notify:
        return service, patch_send, patch_notify

  def test_patched(self):
    service, patch_send, patch_notify = self._patched_service()
    service.do_something()
    patch_send.assert_called_once()
    patch_notify.assert_called_once()

这会失败,因为它调用的是 real 方法而不是修补过的方法。

为了简化,在下面的测试中,第三个选项失败了,我试图弄清楚为什么以及是否有一个好方法来做我想做的事?

from unittest.mock import patch

class ExampleClass:
    def __init__(self):
        self.value = 0

    def add(self, value):
        self.value += self._add(value)

    def subtract(self, value):
        self.value -= self._subtract(value)

    def what_is_my_value(self):
        return self.value

    def _add(self, value):
        return value

    def _subtract(self, value):
        return value

def patch_me(exa: ExampleClass):
    with patch.object(exa, '_add', return_value=99):
        with patch.object(exa, '_subtract', return_value=66):
            return exa

class TestPatchingWorks:

    def test_unpatched_works(self):
        exa = ExampleClass()
        exa.add(5)
        exa.subtract(2)
        assert exa.what_is_my_value() == 3

    def test_patching_works_with_patch_class(self):
        exa = ExampleClass()
        with patch.object(ExampleClass, '_add', return_value=30):
            with patch.object(ExampleClass, '_subtract', return_value=10):
                assert exa.what_is_my_value() == 0
                exa.add(5)
                assert exa.what_is_my_value() == 30
                exa.subtract(2)
                assert exa.what_is_my_value() == 20

    def test_patching_works_with_patch_instance(self):
        exa = ExampleClass()
        with patch.object(exa, '_add', return_value=40):
            with patch.object(exa, '_subtract', return_value=30):
                assert exa.what_is_my_value() == 0
                exa.add(5)
                assert exa.what_is_my_value() == 40
                exa.subtract(2)
                assert exa.what_is_my_value() == 10

    def test_patching_works_with_function(self):
        exa = ExampleClass()
        exa = patch_me(exa)
        assert exa.what_is_my_value() == 0
        exa.add(5)
        assert exa.what_is_my_value() == 99
        exa.subtract(2)
        assert exa.what_is_my_value() == 33

python python-unittest
1个回答
0
投票

嗯,一旦你退出

with
块,补丁就会解开。

@contextlib.contextmanager
def _patched_service(self):
  service = Service()
  with patch.object(service, "_send_to_third_party") as patch_send:
    with patch.object(service, "_notify_listeners") as patch_notify:
      yield service, patch_send, patch_notify

...

def test_patched(self):
  with self._patched_service() as (service, patch_send, patch_notify):
    service.do_something()
    patch_send.assert_called_once()
    patch_notify.assert_called_once()

就可以了。

Pytest 固定装置中也有同样的事情

@pytest.fixture
def patched_service():
  service = Service()
  with patch.object(service, "_send_to_third_party") as patch_send:
    with patch.object(service, "_notify_listeners") as patch_notify:
      yield service, patch_send, patch_notify

def test_patched(patched_service):
  (service, patch_send, patch_notify) = patched_service
  service.do_something()
  patch_send.assert_called_once()
  patch_notify.assert_called_once()
© www.soinside.com 2019 - 2024. All rights reserved.