Как я могу издеваться над объектом модели django?
Например, в моем проекте есть много взаимосвязанных таблиц
class A(models.Model):
name = models.models.CharField(max_length=16)
class B(models.Model):
name = models.models.CharField(max_length=16)
a = models.ForeignKey(A, on_delete=models.CASCADE)
class C(models.Model):
name = models.models.CharField(max_length=16)
b = models.ForeignKey(B, on_delete=models.CASCADE)
и так далее.
Мне нужно протестировать модель C и меня не интересуют модели A и B. Есть ли возможность сделать макет модели B, который можно использовать при создании объектов модели C? Я имею в виду, что я хотел бы создать несколько объектов без создания массивной тестовой базы для тестирования одной крошечной модели.
Если это только для некоторых тестов и вам нужно только несколько экземпляров, вы можете сделать что-то вроде этого:
model_a_instance = A(name='somename')
model_b_instance = B(name='somename2', a=model_a_instance)
model_c_instance = C(name='somename3', b=model_b_instance)
Тем не менее, если вам нужно сохранить модель_c в БД, убедитесь, что модель_a и модель_b также сохранены.
Если вы собираетесь использовать эти модели более широко, я бы рекомендовал создать класс-фабрику для наполнения ваших моделей.
Надеюсь, это помогло.
вы можете использовать пекарню
from model_bakery import baker
AmodelInstance = baker.make(A)
После нескольких дней исследований у меня нет ответа на мой вопрос, но я думаю, что нашел инструмент, который берет на себя заботу о "подготовке базы" перед фактическим тестированием или значительно упрощает ее.
У меня в проекте около 1000 строк тестового кода, и я решил перейти на pytest и переписать тесты почти с нуля, поэтому я делаю то, чего надеялся избежать, но это приемлемо для меня в данном случае.
Вместо создания объектов queryset через django ORM я использую Factory Boy для определения фабрик, которые разрешают отношения с базой данных так, как я хочу.
Для примера я бы реализовал что-то вроде этого:
import factory
class AFactory(factory.django.DjangoModelFactory):
class Meta:
model = A
class BFactory(factory.django.DjangoModelFactory):
class Meta:
model = B
a = factory.SubFactory(AFactory)
class CFactory(factory.django.DjangoModelFactory):
class Meta:
model = C
b = factory.SubFactory(BFactory)
Итак, для тестирования модели C вы просто создаете объект модели C через CFactory.create(), а все "цепочки" обрабатываются с помощью SubFactories.
Однако, модели примеров не имеют никаких ограничений, в отличие от реальных таблиц базы данных. Приведем пример для более наглядного ответа:
class Country(models.Model):
name = models.CharField(choices=(('BY', 'Belarus'), ('UA', 'Ukraine')),
max_length=64, unique=True)
class Employee(models.Model):
name = models.CharField(max_length=64)
email = models.EmailField(max_length=100, unique=True)
country = models.ForeignKey(Country, on_delete=models.CASCADE)
class Supervisor(models.Model):
name = models.CharField(max_length=64)
email = models.EmailField(max_length=100, unique=True)
country = models.ForeignKey(Country, on_delete=models.CASCADE)
employee = models.ForeignKey(Employee, on_delete=models.CASCADE)
Если бы я использовал тот же подход, что и в примере A B C и выполнил что-то вроде SupervisorFactory.create(), то как минимум 2 раза нарушил бы ограничения Country.name и Employee.email. 2 вызова SupervisorFactory попытались бы создать 4 страны, но возможно создать только 3 - 'BY', 'UA', и пустую строку, которая по умолчанию используется фабрикантом. Таким образом, необходимо указать правила, по которым фабрики генерируют данные:
class CountryFactory(factory.django.DjangoModelFactory):
class Meta:
model = Country
django_get_or_create = ('name',)
name = factory.Iterator('BY', 'UA')
class EmployeeFactory(factory.django.DjangoModelFactory):
class Meta:
model = Employee
email = factory.Sequence(lambda nums: 'employee.%04d@employee.io' % nums)
country = factory.SubFactory(CountryFactory)
class Supervisor(factory.django.DjangoModelFactory):
class Meta:
model = Supervisor
email = factory.Sequence(lambda nums: 'supervisor.%04d@supervisor.io' % nums)
country = factory.SubFactory(CountryFactory)
employee = factory.SubFactory(EmployeeFactory)
Надеюсь, это сэкономит ваше время.