在 Pytest-Django 中处理非托管模型
测试非托管模型的挑战
在 Django 项目中,我们偶尔会遇到非托管模型,即元选项中没有 Managed = True 的模型。这些模型可能会使测试变得棘手,特别是当您的测试设置涉及托管和非托管模型或多个数据库的混合时(例如,一个包含托管模型,另一个包含非托管模型)。
这篇博文探讨了使用 pytest-django 测试非托管模型的方法,重点介绍了优点、缺点和解决方法,以帮助您有效管理这些场景。
方法 1:将所有模型标记为托管
在测试期间处理非托管模型的一种直接方法是将它们暂时标记为托管。具体方法如下:
# Add this to conftest.py @pytest.hookimpl(tryfirst=True) def pytest_runtestloop(): from django.apps import apps unmanaged_models = [] for app in apps.get_app_configs(): unmanaged_models += [m for m in app.get_models() if not m._meta.managed] for m in unmanaged_models: m._meta.managed = True
注意:要使此方法发挥作用,您需要在 pytest 设置(或 pytest.ini)中添加 --no-migrations 选项
参考:Stack Overflow
优点:
- 易于实施。
缺点:
- 跳过迁移测试,当多个开发人员处理同一个项目时,这可能会导致问题。
方法 2:手动创建非托管模型
或者,您可以在测试设置期间手动创建非托管模型。这种方法可确保迁移经过测试:
@pytest.fixture(scope="session", autouse=True) def django_db_setup(django_db_blocker, django_db_setup): with django_db_blocker.unblock(): for _connection in connections.all(): with _connection.schema_editor() as schema_editor: setup_unmanaged_models(_connection, schema_editor) yield def setup_unmanaged_models(connection, schema_editor): from django.apps import apps unmanaged_models = [ model for model in apps.get_models() if model._meta.managed is False ] for model in unmanaged_models: if model._meta.db_table in connection.introspection.table_names(): schema_editor.delete_model(model) schema_editor.create_model(model)
优点:
- 将迁移作为测试用例的一部分进行测试。
缺点:
- 稍微复杂一点。
- transaction=True 不适用于此方法(在下一节中讨论)。
了解事务测试
Pytest-django 提供了数据库固定装置:django_db 和 django_db(transaction=True)。它们的区别如下:
django_db: 在测试用例结束时回滚更改,这意味着不会对数据库进行实际提交。
django_db(transaction=True): 在每个测试用例后提交更改并截断数据库表。由于每次测试后只有托管模型会被截断,这就是非托管模型在事务测试期间需要特殊处理的原因。
示例测试用例
@pytest.mark.django_db def test_example(): # Test case logic here pass @pytest.mark.django_db(transaction=True) def test_transactional_example(): # Test case logic here pass
使事务测试适用于非托管模型
由于事务测试仅截断托管模型,因此我们可以在测试运行期间将非托管模型修改为托管模型。这确保它们包含在截断中:
# Add this to conftest.py @pytest.hookimpl(tryfirst=True) def pytest_runtestloop(): from django.apps import apps unmanaged_models = [] for app in apps.get_app_configs(): unmanaged_models += [m for m in app.get_models() if not m._meta.managed] for m in unmanaged_models: m._meta.managed = True
使用 on_commit Hooks 避免 transaction=True (如果可能的话)
在涉及 on_commit 挂钩的场景中,您可以通过直接捕获和执行 on_commit 回调来避免使用事务测试,使用 pytest-django(>= v.4.4) 中的固定装置 django_capture_on_commit_callbacks:
@pytest.fixture(scope="session", autouse=True) def django_db_setup(django_db_blocker, django_db_setup): with django_db_blocker.unblock(): for _connection in connections.all(): with _connection.schema_editor() as schema_editor: setup_unmanaged_models(_connection, schema_editor) yield def setup_unmanaged_models(connection, schema_editor): from django.apps import apps unmanaged_models = [ model for model in apps.get_models() if model._meta.managed is False ] for model in unmanaged_models: if model._meta.db_table in connection.introspection.table_names(): schema_editor.delete_model(model) schema_editor.create_model(model)
参考
- pytest-django 文档
- Stack Overflow:测试非托管模型
您还有其他处理非托管模型的方法或技巧吗?在下面的评论中分享它们!
以上是在 Pytest-Django 中处理非托管模型的详细内容。更多信息请关注PHP中文网其他相关文章!

热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

Video Face Swap
使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热门文章

热工具

记事本++7.3.1
好用且免费的代码编辑器

SublimeText3汉化版
中文版,非常好用

禅工作室 13.0.1
功能强大的PHP集成开发环境

Dreamweaver CS6
视觉化网页开发工具

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)

使用FiddlerEverywhere进行中间人读取时如何避免被检测到当你使用FiddlerEverywhere...

如何在10小时内教计算机小白编程基础?如果你只有10个小时来教计算机小白一些编程知识,你会选择教些什么�...

攻克Investing.com的反爬虫策略许多人尝试爬取Investing.com(https://cn.investing.com/news/latest-news)的新闻数据时,常常�...

Python3.6环境下加载pickle文件报错:ModuleNotFoundError:Nomodulenamed...

使用Scapy爬虫时管道文件无法写入的原因探讨在学习和使用Scapy爬虫进行数据持久化存储时,可能会遇到管道文�...
