Factory Boy 及相关对象创建

Factory Boy and related objects creation

假设您以这种方式关联了这些 Django 模型:

class Service:
   restaurant = models.ForeignKey(Restaurant)
   hist_day_period = models.ForeignKey(DayPeriod)

class DayPeriod:
   restaurant = models.ForeignKey(Restaurant)

我想创建一个 Service 对象,使用工厂。它应该创建所有 3 个模型,但使用 相同的 餐厅。

使用此代码:

class ServiceFactory(factory.django.DjangoModelFactory):
    class Meta:
        model = Service

    restaurant = factory.SubFactory('restaurants.factories.RestaurantFactory')

    hist_day_period = factory.SubFactory(
        'day_periods.factories.DayPeriodFactory', restaurant=restaurant)

工厂男孩将创建 2 家不同的餐厅:

s1 = ServiceFactory.create()
s1.restaurant == s1.hist_day_period.restaurant
>>> False

知道怎么做吗?我不清楚是否应该使用 related factors 而不是 SubFactory 来完成此操作。

我反复讨论过从工厂内部或单独创建相关对象或 FK 对象是否有意义。正如您已经发现的那样,您不一定 想要 每次致电 ServiceFactory() 时都能找到一家新餐厅。我认为您最好让它们保持简单,但代价是不得不使用稍微冗长的调用代码。

注释掉 restaurant = factory.SubFactory 行,然后像这样给您的工厂打电话:

restaurant = Restaurant.objects.get(foo='bar')
ServiceFactory.create_batch(3, restaurant=restaurant)

或者,如果您确实想使用工厂来创建餐厅,但您只想创建一个餐厅:

restaurant = RestaurantFactory()
ServiceFactory.create_batch(3, restaurant=restaurant)

IOTW,让你的工厂做出尽可能少的假设,这样你就可以灵活地构建你需要的任何数据结构,这些数据结构来自测试或系统的不同部分。

您想使用 factoryboy 的 parentsSelfAttribute

class ServiceFactory(factory.django.DjangoModelFactory):
    class Meta:
        model = Service

    restaurant = factory.SubFactory('restaurants.factories.RestaurantFactory')

    hist_day_period = factory.SubFactory(
        'day_periods.factories.DayPeriodFactory',
        restaurant=factory.SelfAttribute('..restaurant')
    )

通过这个测试应用,我得到了

In [1]: from service.tests import ServiceFactory
In [2]: s1 = ServiceFactory.create()
In [3]: s1.restaurant == s1.hist_day_period.restaurant
Out[3]: True

In [4]: s1.restaurant_id
Out[4]: 4

In [5]: s1.hist_day_period.restaurant_id
Out[5]: 4

您可以使用带有查询集的 Iterator 而不是 SubFactory

例如:

class ServiceFactory(factory.django.DjangoModelFactory):
    class Meta:
        model = Service

    restaurant = factory.Iterator(models.Restaurant.object.all())

    hist_day_period = factory.SubFactory(
        'day_periods.factories.DayPeriodFactory', restaurant=restaurant)

不过,我不确定创建 Restaurant 的最佳位置。在我们的代码库中,我重写了 DiscoverRunner 并在那里创建了用于此目的的模型(在 setup_databases 中,这感觉就像是 hack)。