Python mock-修改类属性的mock类方法
我目前有以下要测试的基本Python类:Python mock-修改类属性的mock类方法,python,unit-testing,mocking,python-unittest.mock,pytest-mock,Python,Unit Testing,Mocking,Python Unittest.mock,Pytest Mock,我目前有以下要测试的基本Python类: 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...")
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
我只需创建一个名为mock\u-step(self)
的函数,以避免API调用,并使用新的mock\u-step(self)
函数修补原始的慢速step()
方法
然而,这带来了一个新问题。由于mock\u步骤(self)
函数不是一个mock对象,因此我无法对其调用任何mock方法(例如assert\u called()和call\u count()):
为了解决这个问题,我尝试使用wrapps
参数用模拟对象包装mock\u步骤
:
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()缺少一个必需的位置参数:“self”
因此,从这个阶段开始,我不确定如何断言
step()
在run\u steps()
中被精确调用了4次。对此,有几种解决方案,最简单的可能是使用带有副作用的标准模拟:
def mock_步骤(自):
打印(“跳过浪费时间”)
self.steps+=1
def测试步骤(模拟程序):
示例=示例()
mocked=mocker.patch.object(例如,“步骤”)
mocked.side_effect=lambda:mock_步骤(示例)
示例。运行_步骤()
断言mocked.call\u count==4
side\u effect
可以调用,因此您可以使用标准mock和补丁方法。import unittest.mock as mock
从functools导入部分
def fake_步骤(自):
打印(“伪造”)
self.steps+=1
def test_api():
api=示例()
使用mock.patch.object(api,attribute=“step”,new=partial(fake\u step,self=api)):
#我们需要使用'partial'来模拟实际方法在实例化时绑定了'self'参数
api.run_步骤()
断言api.steps==4
正确输出
“伪造的”
4次。我用导入模拟
测试了您的解决方案,而不是注入模拟
。但是您似乎修补了类对方法的定义,而不是绑定到对象的实际方法,这导致调用浪费时间的代码。@Lenormju-好吧,我按原样测试了代码,它对我有效(例如,不调用生产代码)。我使用mocker是因为问题使用了它,而且使用pytest
更方便。我还想允许使用标准的mock
来允许call\u count
,assert\u call\u xxx
等。而不是自己进行计数(当然,这也是一个解决方案)。你是对的,我没有注意到它出现在OP的代码中,我只需要pip安装pytest mock
,它就工作了。你的解决方案比我的好:)谢谢,这对我很有效。我不知道mocker.patch
返回了一个补丁对象的Mock,所以我从来没有想过要执行类似mocked=mocker.patch.object的操作(例如,“步骤”)
。谢谢你的帮助:)
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
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