首页 > 解决方案 > 有没有合适的方法让工厂男孩连接到测试数据库

问题描述

我在项目的测试套件上遇到了一个非常烦人的错误,因为工厂男孩正在主/默认数据库上运行每个测试用例,而不是在正确的测试数据库上运行查询。

我尝试将 Meta 类配置添加到工厂类(如本文中所推荐),但是一旦我尝试运行 django 测试套件,应用程序就会抛出一个错误,指出与测试数据库的连接不存在。

我将非常感谢任何帮助,因为文档根本不清楚这种情况。

我的设置.py:

DATABASES = {
    "default": {
        "ENGINE": "django.db.backends.mysql",
        "NAME": 'DB_NAME',
        "USER": 'DB_USER',
        "PASSWORD": 'DB_PSSWD',
        "HOST": 'DB_HOST',
        "PORT": 3306,
        "TEST":{
            "NAME": 'TEST_DB_NAME',
        },
        "OPTIONS": {
            "init_command": "SET sql_mode='STRICT_TRANS_TABLES'; SET foreign_key_checks = 0;",
        },
    }
}

我的工厂.py:

import factory

class CustomModelFactory(factory.django.DjangoModelFactory):
    class Meta:
        model = models.CustomModel
        database = 'TEST_DB_NAME'
        django_get_or_create = ('nu_cnpj',)

    nm_razao_social = factory.Faker(locale='pt_BR', provider='company')
    nu_cnpj = factory.Faker(locale='pt_BR', provider='company_id')

我的模型.py:

from django.db import models

class CustomModel(models.Model):
    nu_cnpj = models.CharField(unique=True, max_length=20, blank=True, null=True)
    nm_razao_social = models.CharField(max_length=255, blank=False, null=False)

错误:

python manage.py test flux.tests.test_data_leak_main_db --keepdb
Traceback (most recent call last):
  File "C:\Users\project\venv\lib\site-packages\django\db\utils.py", line 172, in ensure_defaults
    conn = self.databases[alias]
KeyError: 'TEST_DB_NAME'

During handling of the above exception, another exception occurred:
...
    raise ConnectionDoesNotExist("The connection %s doesn't exist" % alias)
django.db.utils.ConnectionDoesNotExist: The connection TEST_DB_NAME doesn't exist

标签: pythondjangotestingfactory-boy

解决方案


最后,我和我的队友能够准确地追踪到是什么工厂实现产生了这种奇怪的行为。工厂类定义中有一个工厂调用,这导致在导入 fase 期间插入数据(这是在创建测试之前默认数据库中的数据库)。因此,工厂的对象被插入到默认数据库中,这是唯一可用于 ORM 的数据库。

错误的实现如下:

import factory

class CustomModelFactory(factory.django.DjangoModelFactory):
    class Meta:
        model = models.CustomModel
        database = 'TEST_DB_NAME'
        django_get_or_create = ('nu_cnpj',)

    nm_razao_social = factory.Faker(locale='pt_BR', provider='company')
    nu_cnpj = factory.Faker(locale='pt_BR', provider='company_id')

    class Params:
        test = factory.Trait(
            nm_razao_social='Test',
        )

class ForeignRelatedCustomModelFactory(factory.django.DjangoModelFactory):

    name = factory.Faker(locale='pt_BR', provider='first_name')
    address = factory.Faker('address')
    status = factory.Faker('pystr')
    fk = factory.SubFactory('CustomModelFactory')

    class Params:
        test = factory.Trait(
            fk=CustomModelFactory(test=True), # this line resulted in a factory call during import, inserting data into the 'default' database instead of the test replica db, during the execution of `python manage.py test`
            name='Test'
        )

推荐阅读