我需要在进行单元测试时,先用模拟方法替换掉我的三个方法(_send_reply
, _reset_watchdog
和 _handle_set_watchdog
),然后再测试我的第四个方法(_handle_command
)的调用。
从查看mock包的文档中,有几种方法可供选择:
使用patch.multiple
作为装饰器
@patch.multiple(MBG120Simulator,
_send_reply=DEFAULT,
_reset_watchdog=DEFAULT,
_handle_set_watchdog=DEFAULT,
autospec=True)
def test_handle_command_too_short_v1(self,
_send_reply,
_reset_watchdog,
_handle_set_watchdog):
simulator = MBG120Simulator()
simulator._handle_command('XA99')
_send_reply.assert_called_once_with(simulator, 'X?')
self.assertFalse(_reset_watchdog.called)
self.assertFalse(_handle_set_watchdog.called)
simulator.stop()
使用patch.multiple
作为上下文管理器
def test_handle_command_too_short_v2(self):
simulator = MBG120Simulator()
with patch.multiple(simulator,
_send_reply=DEFAULT,
_reset_watchdog=DEFAULT,
_handle_set_watchdog=DEFAULT,
autospec=True) as mocks:
simulator._handle_command('XA99')
mocks['_send_reply'].assert_called_once_with('X?')
self.assertFalse(mocks['_reset_watchdog'].called)
self.assertFalse(mocks['_handle_set_watchdog'].called)
simulator.stop()
使用多个patch.object
修饰器
@patch.object(MBG120Simulator, '_send_reply', autospec=True)
@patch.object(MBG120Simulator, '_reset_watchdog', autospec=True)
@patch.object(MBG120Simulator, '_handle_set_watchdog', autospec=True)
def test_handle_command_too_short_v3(self,
_handle_set_watchdog_mock,
_reset_watchdog_mock,
_send_reply_mock):
simulator = MBG120Simulator()
simulator._handle_command('XA99')
_send_reply_mock.assert_called_once_with(simulator, 'X?')
self.assertFalse(_reset_watchdog_mock.called)
self.assertFalse(_handle_set_watchdog_mock.called)
simulator.stop()
使用create_autospec
手动替换方法
def test_handle_command_too_short_v4(self):
simulator = MBG120Simulator()
# Mock some methods.
simulator._send_reply = create_autospec(simulator._send_reply)
simulator._reset_watchdog = create_autospec(simulator._reset_watchdog)
simulator._handle_set_watchdog = create_autospec(simulator._handle_set_watchdog)
# Exercise.
simulator._handle_command('XA99')
# Check.
simulator._send_reply.assert_called_once_with('X?')
self.assertFalse(simulator._reset_watchdog.called)
self.assertFalse(simulator._handle_set_watchdog.called)
个人认为最后一种方法最清晰易读,如果模拟的方法数量增加,也不会导致可怕的长行。它还避免了将simulator
作为第一个(self
)参数传递给assert_called_once_with
。
但我并不觉得它们中的任何一种特别好。特别是多个patch.object
方法的方法,需要仔细匹配嵌套装饰器的参数顺序。
是否有我错过的方法或使其更易读的方法?当您需要在实例/测试类上修补多个方法时,您会怎么做?
@patch('package.module.Class.some_method', autospec=True)
等同于@patch.object(package.module.Class, 'some_method', autospec=True)
吗?如果是这样,我也更喜欢您的方法。 - estansetUp()
和tearDown()
这只是我的个人偏好。我喜欢让每个测试方法都完全独立,这对于那些偶尔只读一遍的读者来说很有帮助,他们不需要导航到setUp()
方法才能完全理解正在发生的事情。 - estan