Django声称post_save信号被调用

时间:2017-05-11 15:46:07

标签: python django unit-testing

我试图声明在保存我的客户端模型实例时调用post_save信号接收器。

信号接收器如下所示:

# reports/signals.py

@receiver(post_save, sender=Client)
def create_client_draft(sender, instance=None, created=False, **kwargs):
    """Guarantees a DraftSchedule exists for each Client post save"""
    print('called')  # Log to stdout when called
    if created and not kwargs.get('raw', False):
        DraftSchedule.objects.get_or_create(client=instance)

我已经设置了一个看起来像这样的测试

@pytest.mark.django_db
@patch('reports.signals.create_client_draft')
def test_auto_create_draftschedule_on_client_creation(mock_signal):
    client = mixer.blend(Client)  # Creates a Client with random data
    assert mock_signal.call_count == 1

我希望这个测试能够通过,因为在运行测试时,called打印语句出现在捕获的标准输出中。

然而,测试运行者似乎认为我的模拟函数从未被调用过。

mock_signal = <MagicMock name='create_client_draft' id='139903470431088'>

    @pytest.mark.django_db
    @patch('reports.signals.create_client_draft')
    def test_auto_create_draftschedule_on_client_creation(mock_signal):
        client = mixer.blend(Client)
>       assert mock_signal.call_count == 1
E       AssertionError: assert 0 == 1
E        +  where 0 = <MagicMock name='create_client_draft' id='139903470431088'>.call_count

reports/tests/test_signals.py:36: AssertionError
---------------------------------------------------------------------------------------------------------------------------------------------------- Captured stdout call -----------------------------------------------------------------------------------------------------------------------------------------------------
called

print语句似乎暗示在测试期间调用了该函数,而测试断言则暗示其他情况。我是否因为模拟库而错过了一些明显的东西?

1 个答案:

答案 0 :(得分:2)

修补模拟对象仅适用于在运行时查找方法的调用者。信号处理程序保存在表格中,因此它们不会查找您的模拟版本。

有点hacky,但你可以让你的信号处理程序调用辅助函数。然后可以模拟辅助函数。

# reports/signals.py

@receiver(post_save, sender=Client)
def create_client_draft_handler(sender, instance=None, created=False, **kwargs):
    create_client_draft(sender, instance, created, **kwargs)

def create_client_draft(sender, instance=None, created=False, **kwargs):
    """Guarantees a DraftSchedule exists for each Client post save

        This function can be mocked, because it's called by name.
    """
    print('called')  # Log to stdout when called
    if created and not kwargs.get('raw', False):
        DraftSchedule.objects.get_or_create(client=instance)