Python 2.7 макет пустой метод класса - PullRequest
0 голосов
/ 18 ноября 2018

Я пытаюсь использовать unittests.mock для имитации вызова метода void объекта.

Мой пакет похож на ниже

common
  baseupgradehandler.py

baseupgradehandler.py

class BaseUpgradeHandler(object):
    def __init__(self, upgrade_config, upgrade_state, system_config, pre_step, main_step, post_step):
        ...

    # Method call to be supressed
    def start(self, service_manifest, upgrade_bundle):
        # type: (service_version_pb2.ServiceManifest, str) -> ()
        ...

В своем тестовом коде я пытаюсь смоделировать вызов start(), как показано ниже, как описано в документации .

from workflow.upgradeworkflow import UpgradeWorkflow
from common.serviceregistry import ServiceRegistry
# The above imports are at the start of the test file
...
with patch('common.baseupgradehandler.BaseUpgradeHandler') as handler_mock:  # type: Mock
    handler_mock.return_value.start.return_value = ''                    
    wf = UpgradeWorkflow(ServiceRegistry(self.service_bundle, config, sys_config, state),
                         config,
                         state,
                         sys_config)

BaseUpgradeHandlerобъект возвращается get_upgrade_handler() методом ServiceRegistry.Когда я выполняю приведенный выше код в тесте, я вижу, что BaseUpgradeHandler.start() все еще вызывается.

Может кто-нибудь дать мне знать, как я могу посмеяться над вызовом start(), чтобы метод не вызывался?

РЕДАКТИРОВАТЬ

Если я изменю свой код исправления, как показано ниже, он будет работать, как ожидалось, и BaseUpgradeHandler будет издеваться, а start не вызываться.

with patch('common.baseupgradehandler.BaseUpgradeHandler') as handler_mock:  # type: Mock
    handler_mock.return_value.start.return_value = ''
    with patch('common.serviceregistry.ServiceRegistry') as serviceregistry_mock:  # type: Mock
        serviceregistry_mock.return_value.get_upgrade_handler.return_value = handler_mock
        wf = UpgradeWorkflow(ServiceRegistry(self.service_bundle, config, sys_config, state), config, state, sys_config)
        wf.start()

Может кто-нибудь объяснить мне, почему я должен также исправлять ServiceRegistry?

1 Ответ

0 голосов
/ 18 ноября 2018

Введенного вами кода недостаточно, чтобы увидеть ту часть, которая вызывает проблему.Нам нужно увидеть модуль serviceregistry, чтобы быть уверенным, но я бы сделал обоснованное предположение:

У вас есть файл a.py (он же baseupgradehandler), подобный этому:

class A:
    def method(self):
        print("It's real!")

И файл b.py (он же serviceregistry), подобный этому:

from a import A

class B:
    def get_A(self):
        return A()

В ваших тестовых файлах вы делаете это:

import unittest
from unittest.mock import patch
from b import B
from a import A

GAME OVER!

Модуль B уже получил ссылку на исходный класс A.Когда впоследствии , вы patch('a.A') только , ссылка в модуле a изменяется, но patch не может знать, что B имеет свою собственную ссылку наисходный A.

Вы можете исправить это тремя способами:

  • исправьте метод: это изменит существующий класс, так что все ссылки на этот класс будут автоматически исправлены
  • исправление b.A тоже:

    with patch('a.A') as h_a, patch('b.A') as h_b:
        h_a.return_value.method.return_value = ''
        h_b.return_value.method.return_value = ''
    
  • Избегайте импорта модулей перед исправлением (возможно, это не осуществимо или не очень хорошая идея):

    import unittest
    from unittest.mock import patch
    
    class MyTest(unittest.TestCase):
        def test_one(self):
            with patch('a.A') as h:
                h.return_value.method.return_value = ''
                from b import B
                B().get_A().method()
    
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...