Python django工厂与OneToOne关系的男孩工厂及相关领域

Python django工厂与OneToOne关系的男孩工厂及相关领域,python,django,testing,factory-boy,Python,Django,Testing,Factory Boy,我正在使用为我的django应用程序创建测试工厂。我遇到问题的模型是一个非常基本的帐户模型,它与django用户身份验证模型(使用django

我正在使用为我的django应用程序创建测试工厂。我遇到问题的模型是一个非常基本的帐户模型,它与django用户身份验证模型(使用django<1.5)有一个OneToOne关系:

这里是我的工厂:

# 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)
因此,我希望factory boy在调用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
文档中确实提到在处理循环导入时要注意循环,但我不确定这是不是真的,也不知道我会如何补救


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

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

也可以考虑将一个序列附加到name字段,这样,如果您确实需要一个以上的帐户,它将自动生成。


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

要将调用
UserFactory的结果传递给
AccountFactory
您应该使用
工厂相关的名称
()

上面的代码在下一步起作用:

  • AccountFactory
    用于实例化需求
    子工厂(UserFactory)
  • UserFactory
    实例化用户
  • UserFactory
    实例化调用后
    RelatedFactory(AccountFactory)
  • 递归,。。由于唯一用户名约束(您可能希望通过或生成用户名),这一点被打破
因此,您需要这样编写
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)

仅供参考,即使没有
post_save
信号,也会发生此错误。您的权利,我已经根据编辑了代码示例,请参见:。文档中有两个子工厂,而不是一个关联工厂和一个子工厂。也许这会引起问题?
user_with_account = UserFactory(generate_account=True)