首页 > 后端开发 > Python教程 > 在 Pytest-Django 中处理非托管模型

在 Pytest-Django 中处理非托管模型

Susan Sarandon
发布: 2024-12-31 08:34:14
原创
311 人浏览过

Handling Unmanaged Models in 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中文网其他相关文章!

来源:dev.to
本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
作者最新文章
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板