factory_boy中的多对多关系?

时间:2013-01-24 22:26:11

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

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

当我在调试器中运行测试时,我可以看到'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')

2 个答案:

答案 0 :(得分:16)

我相信您需要使用@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

答案 1 :(得分:4)

只需使用调音台:

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')

简单,可配置,更快,无模式,声明,您可以在某些测试中获得所需的内容。