Django使用pytest时未创建测试库且测试数据位置不明的问题
问题根因
你的异常是三层配置与代码缺陷叠加导致的,完全不符合pytest-django的测试隔离预期:
1. 核心配置缺失,测试库创建逻辑未触发
pytest-django的test_前缀独立测试库创建机制,仅在插件正常加载、且测试代码被标记为允许数据库访问时才会触发。
你当前的配置存在基础缺陷:
- 仅在pytest.ini中配置了
DJANGO_SETTINGS_MODULE,但未确认pytest-django插件是否正常安装、被pytest进程加载。如果插件未加载,@pytest.mark.django_db只是一个无实际作用的自定义标记,不会执行任何数据库拦截、测试库切换、事务回滚的逻辑。 - 这种场景下,所有测试代码会直接按照settings.py中的数据库配置连接原有
loc_db业务库,完全不会触发test_loc_db的创建流程,所有写入操作直接落到生产业务库中。
2. 自定义序列化器逻辑存在冗余,导致测试结果失真
你实现的BulkUpdateOrCreateListSerializer批量创建逻辑存在重复写入问题:
- 循环调用
self.child.create(attrs)时,每个子序列化器接收到的data是单个字典,会触发SnippetSerializer.create方法中的instance.save()逻辑,每循环一次就向数据库写入一条持久化记录。 - 拿到所有已持久化的实例后,又额外执行一次
bulk_create批量插入,这一步理论上会触发主键重复的完整性约束错误。 - 你看到测试用例“判定通过”,本质是因为没有测试隔离逻辑拦截请求执行,错误未被正确捕获返回,导致200类的成功响应通过了状态码断言。
3. 测试数据存储位置确认
因为没有触发测试库创建流程,测试运行中写入的所有Snippet数据,都会永久保存在原有loc_db库的snippet_snippet表中,直接查询该表即可定位到所有测试残留数据。
修复方案
- 第一步:补全pytest-django基础配置
- 安装依赖:
pip install pytest-django - 执行
pytest --version确认插件加载状态,输出的插件列表中需要存在django项。 - 插件正常加载后,第一次产生数据库连接时,会自动按照Django规则创建
test_loc_db测试库,执行过程中会在控制台打印Creating test database for alias 'default'...的日志。
- 安装依赖:
- 第二步:修正批量序列化逻辑
去掉重复写入的冗余代码,简化批量创建流程:class BulkUpdateOrCreateListSerializer(serializers.ListSerializer): def create(self, validated_data): try: # 直接构造未持久化的模型实例,一次性批量插入 instances = [self.child.Meta.model(**attrs) for attrs in validated_data] return self.child.Meta.model.objects.bulk_create(instances) except IntegrityError as e: raise ValidationError(e) class SnippetSerializer(serializers.ModelSerializer): class Meta: model = Snippet fields = ['id','title', 'code', 'linenos'] read_only_fields = ['id'] list_serializer_class = BulkUpdateOrCreateListSerializer - 第三步:验证测试隔离效果
可在测试用例中加入临时校验逻辑,确认当前使用的是独立测试库而非原业务库:
测试执行完成后,pytest-django会自动销毁测试库,不会在原业务库中残留测试数据。from django.db import connection @pytest.mark.django_db def test_update_snippet(factory, snippets): # 临时验证数据库连接目标 assert connection.settings_dict['NAME'] == 'test_loc_db' request = factory.post('/add-snippets/', snippets) view = SnippetUpdateView.as_view() response = view(request) response.render() assert status.is_success(response.status_code)
内容的提问来源于stack exchange,提问作者BigBoy1337
相关产品推荐
相关产品推荐

