【问题标题】:Many-to-many relationship in factory_boy?factory_boy 中的多对多关系?
【发布时间】:2013-01-08 20:02:48
【问题描述】:

我正在尝试使用 factory_boy 测试两个 Django 模型之间的多对多关系。 factory_boy 文档似乎没有讨论这个问题,我无法弄清楚我做错了什么。当我运行第一个测试时,我收到错误“AttributeError: 'Pizza' object has no attribute 'topping'”。我在第二次测试中遇到了类似的错误。

当我在调试器中运行测试时,我可以看到一个“toppings”对象,但它不知道如何从中获取名称。我是否正确定义了 PizzaFactory 的 _prepare 方法?当您具有多对多关系时,如何从另一个表访问一个表中的名称?

谢谢。

models.py:

from django.db import models

class Topping(models.Model):
    name = models.CharField(max_length=50)

    def __unicode__(self):
        return self.name

class Pizza(models.Model):
    name = models.CharField(max_length=100)
    toppings = models.ManyToManyField(Topping)

    def __unicode__(self):
        return self.name

factories.py:

import factory
from models import Topping, Pizza

class ToppingFactory(factory.Factory):
    name = 'mushrooms'

class PizzaFactory(factory.Factory):
    name = 'Vegetarian'

    @classmethod
    def _prepare(cls, create, **kwargs):
        topping = ToppingFactory()
        pizza = super(PizzaFactory, cls)._prepare(create, **kwargs)
        pizza.toppings.add(topping)
        return pizza

tests.py

​​>
from django.test import TestCase
import factory
from app.models import Topping, Pizza
from app.factories import ToppingFactory, PizzaFactory

class FactoryTestCase(TestCase):

    def test_pizza_has_mushrooms(self):
        pizza = PizzaFactory()
        self.assertTrue(pizza.topping.name, 'mushrooms')

    def test_mushrooms_on_pizza(self):
        topping = ToppingFactory()
        self.assertTrue(topping.pizza.name, 'Vegetarian')

【问题讨论】:

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


    【解决方案1】:

    我相信你需要使用@factory.post_generation装饰器:

    class PizzaFactory(factory.Factory):
        name = 'Vegetarian'
    
        @factory.post_generation
        def toppings(self, create, extracted, **kwargs):
            if not create:
                # Simple build, do nothing.
                return
    
            if extracted:
                # A list of groups were passed in, use them
                for topping in extracted:
                    self.toppings.add(topping)
    

    然后你会在tests.py中调用它pizza = PizzaFactory.create(toppings=(topping1, topping2, tooping3))

    来自https://factoryboy.readthedocs.org/en/latest/recipes.html

    【讨论】:

      【解决方案2】:

      改用混音器:

      from mixer.backend.django import mixer
      
      # Generate toppings randomly
      pizza = mixer.blend(Pizza, toppings=mixer.RANDOM)
      
      # Set toppings
      toppings = mixer.cycle(3).blend(Topping)
      pizza = mixer.blend(Pizza, toppings=toppings)
      
      # Generate toppings with name=tomato
      pizze = mixer.blend(Pizza, toppings__name='tomato')
      

      简单、可配置、更快、无模式、声明性,您可以在一些测试中得到您想要的。

      【讨论】:

      • 支持轶事——为什么我选择mixer...我最初被factory_boy 所吸引。我喜欢factory_boy 中的方式,对于给定的Factory,您可以调用方法attributes() 并返回dict,非常适合与dataset 一起使用。但是mixer 的优点在于它可以帮助你保持干爽,因为它可以在运行中做这么多事情。这意味着如果您的被测代码在未来发生变化,需要更改的测试代码将更少!
      • 你们还支持吗?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-06-15
      • 2011-06-02
      • 2011-02-07
      • 2015-12-30
      • 2020-12-05
      • 2018-09-28
      • 2017-05-22
      相关资源
      最近更新 更多