在Pytest测试Django项目时配置文件型SQLite数据库的Fixture实现及KeyError: 'MIRROR'错误解决
解决pytest-django测试中KeyError: 'MIRROR'的问题
错误原因分析
你遇到的KeyError: 'MIRROR'是因为Django在初始化测试环境时,会自动为每个数据库的TEST配置字典填充默认键(比如MIRROR,默认值为空字符串)。当你直接给settings.DATABASES["default"]["TEST"]赋值一个全新字典时,完全覆盖了Django生成的默认配置,导致系统找不到必需的MIRROR键,从而抛出异常。
修正后的Fixture方案
不要直接替换整个TEST字典,而是用update()方法修改需要的字段,保留原有的默认配置项:
import os import pytest @pytest.fixture(scope="function") def file_based_db(settings): """Fixture to switch to file-based SQLite databases for specific tests""" # 更新TEST配置而非完全替换,保留Django默认的键值对 settings.DATABASES["default"]["TEST"].update({ "ENGINE": "django.db.backends.sqlite3", "NAME": "default_db.sqlite3", }) settings.DATABASES["other_db"]["TEST"].update({ "ENGINE": "django.db.backends.sqlite3", "NAME": "other_db.sqlite3", }) yield # 执行测试用例 # 测试完成后自动清理数据库文件,避免冗余文件堆积 for db_file in ["default_db.sqlite3", "other_db.sqlite3"]: if os.path.exists(db_file): os.remove(db_file)
为什么这样有效?
update()方法只会修改你指定的NAME和ENGINE字段,不会删除Django自动添加的MIRROR等默认键,完美契合Django测试环境的配置要求,从根源上避免了KeyError。
额外优化建议
- 如果你不想让数据库文件存放在项目根目录,可以用
tempfile模块生成临时文件路径,进一步隔离测试环境:import tempfile # 在fixture中替换NAME为临时文件路径 with tempfile.NamedTemporaryFile(suffix=".sqlite3", delete=False) as tmp_default: settings.DATABASES["default"]["TEST"]["NAME"] = tmp_default.name with tempfile.NamedTemporaryFile(suffix=".sqlite3", delete=False) as tmp_other: settings.DATABASES["other_db"]["TEST"]["NAME"] = tmp_other.name - 除了用
@pytest.mark.usefixtures标记测试类,也可以直接在测试方法中传入fixture,写法更直观:class ThingForm(TransactionTestCase): def test_empty_form_fields(self, file_based_db): self.thing = Thing.objects.create(name="thing1") form = MyForm() self.assertIn("created_by", form.fields) self.assertIn("deleted_at", form.fields) self.assertIn("updated_by", form.fields)
内容的提问来源于stack exchange,提问作者Hanny
相关产品推荐
相关产品推荐

