简体   繁体   English

测试 django `post_save` 信号,该信号包括在提交 db 事务后发生的函数调用

[英]Testing a django `post_save` signal that includes function calls that occur after db transaction is committed

When django tests are running, database transactions are not committed.运行 django 测试时,不会提交数据库事务。 How do I test an event triggered by object creation but that happens after the db transaction has been committed?如何测试由对象创建触发但在提交 db 事务后发生的事件?

I have a Campaign model and the below post_save signal.我有一个Campaign模型和下面的post_save信号。 Using Django TestCase it is difficult to assert that the functions within transaction.on_commit are called in the case when a new Campaign object is created.使用 Django TestCase 很难断言在创建新的 Campaign 对象时调用了transaction.on_commit中的函数。 When the signal runs in the test context, it always thinks that an existing campaign object is being edited, not that one has been newly created.当信号在测试上下文中运行时,它总是认为正在编辑现有的活动对象,而不是新创建的对象。 Therefore I cannot test the else branch of the if statement.因此我无法测试 if 语句的else分支。

How could I test the case when Campaign.objects.filter(pk=instance.pk).exists() is False?Campaign.objects.filter(pk=instance.pk).exists()为 False 时,我如何测试案例?

Signal:信号:

@receiver(post_save, sender=Campaign, dispatch_uid="apps.writing.signals.create_handwriting")
def create_handwriting(sender, instance, **kwargs):
    """Whenever a campaign is created or updated, trigger the handwriting cloud function to (re)generate the
    handwriting image.
    """

    if Campaign.objects.filter(pk=instance.pk).exists():
        transaction.on_commit(
            lambda: log_campaign_progress(pk=instance.pk, status="t2h-edited", stage="campaign")
        )
        transaction.on_commit(lambda: delete_campaign_pages(campaign_pk=instance.pk))
    else:
        transaction.on_commit(
            lambda: log_campaign_progress(pk=instance.pk, status="t2h-created", stage="campaign")
        )

    transaction.on_commit(lambda: enqueue_handwriting_generation(campaign_pk=instance.pk))

Test:测试:

class TestSignals(TestCase):
    def setUp(self):
        self.factory = RequestFactory()

    @mock.patch("lettergun.apps.writing.signals.log_campaign_progress")
    @mock.patch("lettergun.apps.writing.signals.enqueue_handwriting_generation")
    @mock.patch("lettergun.apps.writing.signals.delete_campaign_pages")
    def test_create_handwriting_edit_existing_campaign(
        self, delete_campaign_pages, enqueue_handwriting_generation, log_campaign_progress
    ):
        # disconnected in the factory so we need to reconnect it here
        signals.post_save.connect(
            sender=Campaign,
            dispatch_uid="apps.writing.signals.create_handwriting",
            receiver=create_handwriting,
        )
        enqueue_handwriting_generation.return_value = True
        log_campaign_progress.return_value = True

        with self.captureOnCommitCallbacks(execute=True) as callbacks:
            user = G(User)
            campaign = G(Campaign, user=user)

        assert Campaign.objects.get(pk=campaign.pk)
        assert Campaign.objects.filter(pk=campaign.pk).exists()

        enqueue_handwriting_generation.assert_called_with(campaign_pk=campaign.pk)
        log_campaign_progress.assert_called_with(pk=campaign.pk, stage="campaign", status="t2h-edited")
        delete_campaign_pages.assert_called_with(campaign_pk=campaign.pk)

django.test.TestCase does not support transactions (there is a performance penalty with committing a database transaction and cleaning after test). django.test.TestCase不支持事务(提交数据库事务和测试后清理会降低性能)。 As per https://docs.djangoproject.com/en/4.0/topics/testing/tools/#django.test.TestCase根据https://docs.djangoproject.com/en/4.0/topics/testing/tools/#django.test.TestCase

  • Wraps the tests within two nested atomic() blocks: one for the whole class and one for each test.将测试包装在两个嵌套的 atomic() 块中:一个用于整个类,一个用于每个测试。 Therefore, if you want to test some specific database transaction behavior, use TransactionTestCase .因此,如果您想测试一些特定的数据库事务行为,请使用TransactionTestCase

You should use TransactionTestCase https://docs.djangoproject.com/en/4.0/topics/testing/tools/#django.test.TransactionTestCase您应该使用TransactionTestCase https://docs.djangoproject.com/en/4.0/topics/testing/tools/#django.test.TransactionTestCase

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM