我应该如何测试在一个循环中调用了多个函数?

时间:2018-11-14 07:17:24

标签: python django unit-testing testing mocking

如何确保在循环中调用所有处理程序?我想到的最好的办法是模拟<CalendarDatePicker CalendarIdentifier="JapaneseCalendar"/>函数,并检查该函数是否被调用了一定次数,但是我认为可能会有更好的解决方案。

<CalendarDatePicker CalendarIdentifier="JapaneseCalendar"/>

测试:

fake_handler

1 个答案:

答案 0 :(得分:1)

我在测试中发现了许多问题,总之,您不应该打补丁,而测试太少。让我一一解决。

请勿打补丁

确实,这是一个犯错或陷入许多警告中的巨大机会。几乎每个教程都从使用修补程序开始,以测试难以测试的代码。但是您的代码是可测试的,并且您不需要它,它将同样有效:

def test_handle(self):
    handler = mock.Mock(name='handler')
    messages = MessageHandler([handler, handler])
    messages.handle(None, None)
    self.assertEqual(handler.call_count, 2)

检查在对模拟的调用中传递的参数

您的测试检查是否两次调用了处理程序,但没有传递参数。您宁愿检查是否传递了正确的参数。

def test_handle(self):
    handler = mock.Mock(name='handler')
    messages = MessageHandler([handler, handler])
    messages.handle(None, None)
    self.assertEqual(
        handler.mock_calls,
        [mock.call(None, None), mock.call(None, None)]
    )

实际检查参数

我们现在正在检查None是否已传递给处理程序,但事件和主体均为None,其他任何内容也可能为None,因此我们真的不知道是否该代码是正确的选择。最好为每个参数使用不同的唯一值。

def test_handle(self):
    handler = mock.Mock(name='handler')
    messages = MessageHandler([handler, handler])
    messages.handle(mock.sentinel.event, mock.sentinel.body)
    self.assertEqual(
        handler.mock_calls,
        [mock.call(mock.sentinel.event, mock.sentinel.body),
         mock.call(mock.sentinel.event, mock.sentinel.body)]
    )

使用不同的处理程序进行测试

有两次相同的处理程序是一个极端的情况。即使您可能希望保留此测试(或更改它;是否真的要允许重复的处理程序?),您也确实想测试处理程序不同的一般情况。

def test_handle(self):
    handler1 = mock.Mock(name='handler1')
    handler2 = mock.Mock(name='handler2')
    messages = MessageHandler([handler1, handler2])
    messages.handle(mock.sentinel.event, mock.sentinel.body)
    handler1.assert_called_once_with(
        mock.sentinel.event, mock.sentinel.body
    )
    handler2.assert_called_once_with(
        mock.sentinel.event, mock.sentinel.body
    )

检查是否按顺序调用了处理程序

如果要断言调用是按顺序进行的,则上述测试还不够。如果更改断言的顺序,它仍然会通过。我知道检查不同模拟程序调用顺序的唯一方法是使它们成为同一父模拟程序的属性。这一点都不让我感到高兴,因为测试变得与与我要测试的行为无关的对象有关,但这似乎是唯一的方法。

def test_handle(self):
    handlers_parent = mock.Mock(name='handlers_parent')
    handler1 = handlers_parent.handler1
    handler2 = handlers_parent.handler2
    messages = MessageHandler([handler1, handler2])
    messages.handle(mock.sentinel.event, mock.sentinel.body)
    self.assertEqual(
        handlers_parent.mock_calls,
        [mock.call.handler1(mock.sentinel.event, mock.sentinel.body),
         mock.call.handler2(mock.sentinel.event, mock.sentinel.body)]
    )