【问题标题】:Factory Boy and related objects creationFactory Boy 和相关对象的创建
【发布时间】:2018-05-08 13:14:46
【问题描述】:

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

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

class DayPeriod:
   restaurant = models.ForeignKey(Restaurant)

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

使用此代码:

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 来完成此操作。

【问题讨论】:

    标签: python django unit-testing factory factory-boy


    【解决方案1】:

    我反复讨论了从工厂内部或单独创建相关对象或 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,让您的工厂做出尽可能少的假设,这样您就可以灵活地从测试或系统的不同部分构建您需要的任何数据结构。

    【讨论】:

    • 感谢@shacker,您的回答帮助我提升了一些高度,我认为您对灵活性的看法是正确的。然而,恐龙华尔兹的答案正是我想做的技术方法:)
    【解决方案2】:

    你想使用 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
    

    【讨论】:

    • 不清楚这如何解决 OP 创建三个 Service 记录但只有一个 Restaurant 记录的问题。
    • OP 声明“它应该创建所有 3 个模型,但使用同一家餐厅。”。我将其读为ServiceResturantDayPeriod,但只有一个Restaurant,他提供的代码示例看起来支持了这一点
    • 好答案,我认为在这里提及lazyattribute并解释使用或不使用RelatedFactory的原因也很有意义。
    • 非常感谢,正是我所需要的。你应该得到这个赏金:)
    【解决方案3】:

    您可以使用带有查询集的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)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-04-09
      • 1970-01-01
      • 1970-01-01
      • 2020-08-21
      • 1970-01-01
      • 1970-01-01
      • 2021-10-04
      • 2020-07-24
      相关资源
      最近更新 更多