如何用pytest将含预定义主键的Status模型fixture加载至Django测试数据库?
在pytest中加载Django遗留fixture数据的方案
背景
我维护一段遗留代码,其中Status模型的初始数据(含预定义主键)存储在status_data.json文件中,可通过python manage.py loaddata <fixturename>命令加载,数据示例:
{ "model": "status.Status", "pk":4, "fields": { "item": "Achat", "table": "billing_models", "attribute": "status_billing_models" } }
部分模型与Status模型存在外键关联,且Status的主键为静态值,示例代码:
class BillingModel(Timestemps, SafeDeleteModel): ACHAT = 4 ACTIVATION = 5 name = models.CharField(max_length=200) # ... 更多字段 # achat or activation cycle_start_at = models.ForeignKey(Status, models.CASCADE)
需要编写该遗留代码的测试,实现通过pytest将这些初始数据加载到Django测试数据库,以便基于该数据编写测试用例。
方法1:测试用例内手动加载
借助pytest-django的django_db标记确保测试能访问数据库,直接调用Django的loaddata命令加载指定fixture:
from django.core.management import call_command import pytest @pytest.mark.django_db def test_billing_model_association(): # 加载status_data.json中的预设数据 call_command('loaddata', 'status_data.json') # 基于已加载的Status数据编写测试逻辑 from myapp.models import BillingModel, Status achat_status = Status.objects.get(pk=BillingModel.ACHAT) test_billing = BillingModel.objects.create( name="测试账单模型", cycle_start_at=achat_status ) assert test_billing.cycle_start_at.item == "Achat"
方法2:全局Fixture自动加载
如果多个测试用例都依赖这些初始数据,可在项目根目录的conftest.py中定义一个fixture,实现自动或按需加载:
自动加载(所有测试执行前加载)
# conftest.py import pytest from django.core.management import call_command @pytest.fixture(autouse=True) def load_default_statuses(django_db_blocker): with django_db_blocker.unblock(): call_command('loaddata', 'status_data.json')
按需加载(仅在测试显式引用时加载)
# conftest.py import pytest from django.core.management import call_command @pytest.fixture def status_fixture(django_db_blocker): with django_db_blocker.unblock(): call_command('loaddata', 'status_data.json')
使用时在测试用例中显式声明:
@pytest.mark.django_db def test_status_existence(status_fixture): from myapp.models import Status assert Status.objects.filter(pk=4).exists()
方法3:通过pytest标记指定加载
先确保fixture文件放在Django识别的目录中:
- 在项目根目录创建
fixtures文件夹 - 在
settings.py中添加配置:
FIXTURE_DIRS = [ BASE_DIR / 'fixtures', ]
然后在测试用例中通过标记直接指定要加载的fixture:
import pytest @pytest.mark.django_db(fixtures=['status_data']) def test_billing_status_link(): from myapp.models import BillingModel, Status assert Status.objects.get(pk=BillingModel.ACHAT).table == "billing_models"
注意事项
- 由于
Status主键是预定义的静态值,测试中创建关联模型时,优先使用模型类中定义的常量(如BillingModel.ACHAT),避免硬编码数字,提升代码可维护性。 - 若fixture文件不在默认识别路径,可在
call_command中传入完整文件路径,比如call_command('loaddata', '/path/to/status_data.json')。
内容的提问来源于stack exchange,提问作者khelalfa rabah
相关产品推荐
相关产品推荐

