我正在为一个大型的Django应用编写测试,作为这个过程的一部分,我正在逐步为Django项目中不同应用的所有模型创建工厂。
然而,我在FactoryBoy中遇到了一些令人困惑的行为,它几乎看起来像
当我尝试运行以下测试时发生错误:
最后一行会失败(
虽然涉及到了许多工厂/模型,但布局相对简单。
下面的
然而,我在FactoryBoy中遇到了一些令人困惑的行为,它几乎看起来像
SubFactories
有一个最大深度,超过该深度将不生成任何实例。当我尝试运行以下测试时发生错误:
def test_subfactories(self):
""" Verify that the factory is able to initialize """
user = UserFactory()
self.assertTrue(user)
self.assertTrue(user.profile)
self.assertTrue(user.profile.tenant)
order = OrderFactory()
self.assertTrue(order)
self.assertTrue(order.user.profile.tenant)
最后一行会失败(
AssertionError: None is not true
),通过调试器运行这个测试可以发现,确实order.user.profile.tenant返回的是None
而不是期望的Tenant
实例。虽然涉及到了许多工厂/模型,但布局相对简单。
User
(django默认)和Profile
模型通过OneToOneField链接在一起,经过一些麻烦之后,由UserFactory
和ProfileFactory
表示。@factory.django.mute_signals(post_save)
class ProfileFactory(factory.django.DjangoModelFactory):
class Meta:
model = yuza_models.Profile
django_get_or_create = ('user',)
user = factory.SubFactory('yuza.factories.UserFactory')
birth_date = factory.Faker('date_of_birth')
street = factory.Faker('street_name')
house_number = factory.Faker('building_number')
city = factory.Faker('city')
country = factory.Faker('country')
avatar_file = factory.django.ImageField(color='blue')
tenant = factory.SubFactory(TenantFactory)
@factory.django.mute_signals(post_save)
class UserFactory(factory.django.DjangoModelFactory):
class Meta:
model = auth_models.User
username = factory.Sequence(lambda n: "user_%d" % n)
first_name = factory.Faker('first_name')
last_name = factory.Faker('last_name')
email = factory.Faker('email')
is_staff = False
is_superuser = False
is_active = True
last_login = factory.LazyFunction(timezone.now)
@factory.post_generation
def profile(self, create, extracted):
if not create:
return
if extracted is None:
ProfileFactory(user=self)
下面的
TenantFactory
在上文的ProfileFactory
中被表示为一个SubFactory
。class TenantFactory(factory.django.DjangoModelFactory):
class Meta:
model = elearning_models.Tenant
name = factory.Faker('company')
slug = factory.LazyAttribute(lambda obj: text.slugify(obj.name))
name_manager = factory.Faker('name')
title_manager = factory.Faker('job')
street = factory.Faker('street_name')
house_number = factory.Faker('building_number')
house_number_addition = factory.Faker('secondary_address')
Order
与 User
相关联,但其许多方法调用了 self.user.profile.tenant
的字段。
class OrderFactory(factory.DjangoModelFactory):
class Meta:
model = Order
user = factory.SubFactory(UserFactory)
order_date = factory.LazyFunction(timezone.now)
price = factory.LazyFunction(lambda: Decimal(random.uniform(1, 100)))
site_tenant = factory.SubFactory(TenantFactory)
no_tax = fuzzy.FuzzyChoice([True, False])
大部分测试中的断言都通过了,所有单独的工厂都能够从其直接的外键关系中初始化获取值。但是,一旦工厂/模型彼此相距三步,调用将返回None而不是预期的Tenant
实例。
因为我在FactoryBoy文档中找不到任何关于这种行为的参考,所以这可能是我的问题,但是到目前为止,我还无法确定它的起源。有人知道我哪里错了吗?
post_save方法
def create_user_profile(sender, instance, created, **kwargs):
if created:
profile = Profile.objects.create(user=instance)
resume = profile.get_resume()
resume.initialize()
post_save.connect(create_user_profile, sender=User)
order.refresh_from_db()
。此外,这些模型中是否有任何自定义的save
方法?PostGeneration(您的User.profile
)在完成之前包括对instance.save()
的调用。Profile
和Tenant
表中是否保存了任何预期的内容? - CoffeeBasedLifeformUserFactory.profile
有些不对劲(是的,我知道问题似乎出在ProfileFactor.tenant
)。如果您使用早期创建的用户实例:order = OrderFactory(user = user)
,测试是否通过? - CoffeeBasedLifeform.refresh_from_db()
没有通过Profile
对象,存在一个 post_save 方法(在我的上面的帖子中包含)来创建一个Profile
在User
创建时。我通过在UserFactory
和ProfileFactory
上使用@factory.django.mute_signals
装饰器来考虑这个信号。OrderFactory
上时,测试通过了!我原以为对Order.user
的任何调用都会触发已经包含装饰器的UserFactory
,但显然这并不够。 - Jasper