簡體   English   中英

Python mock - mocking class 修改 ZA2F2ED4F8EBC2CBB4C21A29DC40AB6DZ 屬性的方法

[英]Python mock - mocking class method that modifies class attributes

我目前有以下要測試的基本 Python class :

class Example:

    def run_steps(self):
        self.steps = 0

        while self.steps < 4:
            self.step()
    
    def step(self):
        # some expensive API call
        print("wasting time...")
        time.sleep(1000)

        self.steps += 1

如您所見,step() 方法包含一個昂貴的 API 調用,因此我想用另一個 function 模擬它,以避免昂貴的 API 調用,但仍然遞增self.steps . 我發現這樣做是可能的(從這里可以看出):

def mock_step(self):
    print("skip the wasting time")
    self.steps += 1

# This code works!
def test(mocker):
    example = Example()
    mocker.patch.object(Example, 'step', mock_step)

    example.run_steps()

我只是創建了一個名為mock_step(self)的 function 來避免 API 調用,然后我使用新的mock_step(self) ZC1C425268E68385D14AB5074C17A 修補原始的慢step()方法。

然而,這導致了一個新的問題。 由於mock_step(self) function 不是 Mock object,因此我無法在其上調用任何 Mock 方法(例如 assert_call() 和 call_count()):

def test(mocker):
    example = Example()
    mocker.patch.object(Example, 'step', mock_step)

    example.run_steps()

    # this line doesn't work
    assert mock_step.call_count == 4

為了解決這個問題,我嘗試使用wraps參數用 Mock object 包裝mock_step

def test(mocker):
    example = Example()

    # this doesn't work
    step = mocker.Mock(wraps=mock_step)
    mocker.patch.object(Example, 'step', step)

    example.run_steps()

    assert step.call_count == 4

但后來我得到一個不同的錯誤,說mock_step() missing 1 required positional argument: 'self'

因此,從這個階段開始,我不確定如何斷言step()run_steps()中被准確地調用了 4 次。

有幾種解決方案,最簡單的可能是使用具有副作用的標准模擬:

def mock_step(self):
    print("skip the wasting time")
    self.steps += 1


def test_step(mocker):
    example = Example()
    mocked = mocker.patch.object(Example, 'step')
    mocked.side_effect = lambda: mock_step(example)
    example.run_steps()
    assert mocked.call_count == 4

side_effect可以采用可調用對象,因此您可以同時使用標准模擬和修補方法。

import unittest.mock as mock
from functools import partial


def fake_step(self):
    print("faked")
    self.steps += 1


def test_api():
    api = Example()
    with mock.patch.object(api, attribute="step", new=partial(fake_step, self=api)):
        # we need to use `partial` to emulate that a real method has its `self` parameter bound at instantiation
        api.run_steps()
    assert api.steps == 4

正確輸出"faked" 4 次。

暫無
暫無

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

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