首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Factory-boy / Django - Factory实例未反映对模型实例的更改

Factory-boy / Django - Factory实例未反映对模型实例的更改
EN

Stack Overflow用户
提问于 2019-08-16 01:07:02
回答 2查看 772关注 0票数 1

我正在为一个我正在工作的网站写测试,我用factoryboy工厂对象来表示模型。

然而,我遇到了一些让我感到困惑的行为,我想知道这里是否有人能如此友好地向我解释一下

我正在运行一个包含以下模型的测试:

代码语言:javascript
复制
STATUS = (
    ('CALCULATING'),
    ('PENDING'),
    ('BUSY'),
    ('SUCCESS'),
    ('FAILED')
)


class SchoolImport(models.Model):
    date = models.DateTimeField(auto_now_add=True)
    status = models.CharField(
        verbose_name=_('status'), choices=STATUS,
        max_length=50, default='CALCULATING'
    )

为此,我创建了以下工厂。正如您所看到的,status被设置为其缺省值,我发现这比随机选择的值更现实

代码语言:javascript
复制
class SchoolImportFactory(factory.DjangoModelFactory):
    class Meta:
        model = models.SchoolImport

    status = 'CALCULATING'
    school = factory.SubFactory(SchoolFactory)

    @factory.lazy_attribute
    def date(self):
        return timezone.now() - datetime.timedelta(days=10)

下面您将看到正在测试的函数的(简化)版本,以及测试本身。(我目前已经注释掉了笔记本电脑上的所有其他代码,因此您在下面看到的函数是一个准确的表示)

它的要点是该函数接收到一个id值,它将使用该值从数据库获取SchoolImport对象并更改其状态。该函数将在celery中运行,因此不会返回任何内容。

当我通过调试器运行此测试时,我可以看到该值已正确更改。但是,当测试运行其最终断言时,它会失败,因为self.school_import.status仍然等于CALCULATING

代码语言:javascript
复制
#app.utils.py
def process_template_objects(school_import_pk):
    school_import = models.SchoolImport.objects.get(id=import_file_pk)
    school_import.status = 'BUSY'
    school_import.save()



#app.tests.test_utils.py
class Test_process_template_objects_function(TestCase):

    def setUp(self):
        self.school = SchoolFactory()
        self.school_import = SchoolImportFactory(
            school=self.school
        )

    def test_function_alters_school_import_status(self):
        self.assertEqual(
            self.school_import.status, 'CALCULATING'
        )
        utils.process_template_objects(self.school_import.id)
        self.assertNotEqual(
            self.school_import.status, 'CALCULATING'
        )

当我通过调试器(在失败的断言之前有一个断点)运行此测试并运行SchoolImport.objects.get(id=self.school_import.id).status时,它确实返回了正确的BUSY值。

因此,尽管由FactoryInstance表示的对象正在正确更新,但更改不会反映在工厂实例本身中。

虽然我意识到我可能在这里做错了什么/遇到了预期的行为,但我想知道使用factoryboy编写测试的人是如何绕过这种行为的,或者是否有一种方法可以“刷新”factoryboy实例以反映对模型实例的更改。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2019-08-16 03:22:16

这个问题源于这样一个事实:在process_template_objects中,您使用的SchoolImport对象实例与测试中的实例不同。

如果您运行以下命令:

代码语言:javascript
复制
a = models.SchoolImport.objects.get(pk=1)
b = models.SchoolImport.objects.get(pk=2)

assert a == b  # True: both refer to the same object in the database
assert a is b  # False: different Python objects, each with its own memory

a.status = 'SUCCESS'
a.save()
assert a.status == 'SUCCESS'  # True: it was indeed changed in this Python object
assert b.status == 'SUCCESS'  # False: the 'b' object hasn't seen the change

为了解决这个问题,您应该在调用process_template_objects之后从数据库中重新获取实例

代码语言:javascript
复制
utils.process_template_objects(self.school_import.id)
self.school_import.refresh_from_db()

有关更详细的解释,请参阅https://docs.djangoproject.com/en/2.2/ref/models/instances/#refreshing-objects-from-database

票数 3
EN

Stack Overflow用户

发布于 2020-01-19 08:16:05

如果从模型实例中删除某个字段,则再次访问该字段时会从数据库中重新加载该值。

代码语言:javascript
复制
obj = MyModel.objects.first()
del obj.field
obj.field  # Loads the field from the database

请参阅https://docs.djangoproject.com/en/2.2/ref/models/instances/#refreshing-objects-from-database

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/57513453

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档