首頁 > 後端開發 > Python教學 > 在 Pytest-Django 中處理非託管模型

在 Pytest-Django 中處理非託管模型

Susan Sarandon
發布: 2024-12-31 08:34:14
原創
297 人瀏覽過

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
作者最新文章
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板