簡體   English   中英

Python 2.7 模擬類的 void 方法

[英]Python 2.7 mock a void method of a class

我正在嘗試使用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對象由ServiceRegistry get_upgrade_handler()方法返回。 當我在測試中執行上述代碼時,我看到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嗎?

您提供的代碼不足以查看導致問題的部分。 我們需要查看模塊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

游戲結束!

B模塊現在已經獲得了對原始A類的引用。 之后,當您patch('a.A')更改了a模塊中的引用,但patch無法知道B對原始A有自己的引用。

您可以通過三種方式解決此問題:

  • 修補方法:這將修改現有類,因此將自動修補對該類的所有引用
  • 補丁bA太:

     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()

我已經使用 unittest.mocks 一段時間了,有時我一直在重新發明輪子。 我決定讓 mockito 成為我項目的一部分,現在事情看起來好多了。 任何類型的模擬驗證都非常簡單,如果可以的話,我絕對鼓勵您將 mockito 用作庫的一部分。 這個庫有一個很好的文檔,到目前為止它比 unittest.mock 恕我直言更容易。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM