【问题标题】:django factory boy factory with OneToOne relationship and related fielddjango factory boy factory 与 OneToOne 关系及相关领域
【发布时间】:2013-07-09 15:02:26
【问题描述】:

我正在使用Factory Boy 为我的 django 应用程序创建测试工厂。我遇到问题的模型是一个非常基本的 Account 模型,它与 django User auth 模型具有 OneToOne 关系(使用 django

# models.py
from django.contrib.auth.models import User
from django.db import models

class Account(models.Model):
    user = models.OneToOneField(User)
    currency = models.CharField(max_length=3, default='USD')
    balance = models.CharField(max_length="5", default='0.00') 

这是我的工厂:

# factories.py
from django.db.models.signals import post_save
from django.contrib.auth.models import User

import factory

from models import Account


class AccountFactory(factory.django.DjangoModelFactory):
    FACTORY_FOR = Account

    user = factory.SubFactory('app.factories.UserFactory')
    currency             = 'USD'
    balance              = '50.00'

class UserFactory(factory.django.DjangoModelFactory):
    FACTORY_FOR = User

    username = 'bob'
    account = factory.RelatedFactory(AccountFactory)

所以我希望工厂男孩在调用 AccountFactory 时创建一个相关的 UserFactory:

# tests.py 
from django.test import TestCase

from factories import AccountFactory

class AccountTest(TestCase):

    def setUp(self):
        self.factory = AccountFactory()

    def test_factory_boy(self):
        print self.factory.id

但是,在运行测试时,似乎正在创建多个用户模型,并且我看到了一个完整性错误:

IntegrityError: column username is not unique

文档确实提到在处理循环导入时要注意循环,但我不确定这是否是怎么回事,也不知道我将如何解决它。 docs

如果任何熟悉 Factory Boy 的人可以插话或提供一些关于可能导致此完整性错误的原因的见解,我们将不胜感激!

【问题讨论】:

  • 仅供参考,即使没有post_save 信号也会发生错误。
  • 你的权利,我已经相应地编辑了代码示例

标签: python django testing factory-boy


【解决方案1】:

我相信这是因为您的工厂定义中有循环引用。尝试从 UserFactory 定义中删除行 account = factory.RelatedFactory(AccountFactory)。如果您总是要通过 AccountFactory 调用帐户创建,则不需要此行。

另外,您可以考虑在名称字段中附加一个序列,这样如果您确实需要多个帐户,它会自动生成它们。

username = "bob" 更改为username = factory.Sequence(lambda n : "bob {}".format(n)),您的用户将被命名为“bob 1”、“bob 2”等。

【讨论】:

【解决方案2】:

要将调用UserFactory 的结果传递给AccountFactory,您应该使用factory_related_name (docs)

上面的代码接下来会起作用:

  • AccountFactory 用于实例化需求 SubFactory(UserFactory)
  • UserFactory 实例化用户。
  • UserFactory 实例化调用后RelatedFactory(AccountFactory)
  • 递归,.. 由于唯一用户名约束而被破坏(您可能希望通过FuzzyTextSequence 生成用户名)

所以你需要这样写UserFactory

class UserFactory(factory.django.DjangoModelFactory):
    account = factory.RelatedFactory(AccountFactory, factory_related_name='user')
    username = factory.Sequence(lambda a: 'email%04d@somedomain.com' % a)
    # rest of code

但您仍然会遇到已编写测试的问题。想象一下,您有如下测试场所:

user = UserFactory()
account = Account(user=user)

然后添加RelatedFactory 将中断测试。如果你的项目中没有很多测试和贡献者,你可以重写它们。但如果不是,它不是一个选择。处理方法如下:

class UserFactory(factory.django.DjangoModelFactory):
    class Params:
        generate_account = factory.Trait(
            account=factory.RelatedFactory(AccountFactory, factory_related_name='user')
        )

那么上面的代码不会被破坏,因为UserFactory的默认调用不会实例化AccountFactory。使用帐户实例化用户:

user_with_account = UserFactory(generate_account=True)

【讨论】:

  • 这不起作用,因为您仍在定义循环引用。 UserFactory 指的是 AccountFactory,反之亦然...
猜你喜欢
  • 1970-01-01
  • 2018-05-08
  • 2019-11-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-04
相关资源
最近更新 更多