在 Django 專案中,我們偶爾會遇到非託管模型,也就是元選項中沒有 Managed = True 的模型。這些模型可能會使測試變得棘手,特別是當您的測試設定涉及託管和非託管模型或多個資料庫的混合時(例如,一個包含託管模型,另一個包含非託管模型)。
這篇部落格文章探討了使用 pytest-django 測試非託管模型的方法,重點介紹了優點、缺點和解決方法,以幫助您有效管理這些場景。
在測試期間處理非託管模型的一種直接方法是將它們暫時標記為託管。具體方法如下:
# 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
優點:
缺點:
或者,您可以在測試設定期間手動建立非託管模型。此方法可確保遷移經過測試:
@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 提供了資料庫固定裝置: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 掛鉤的場景中,您可以透過直接擷取和執行 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 中處理非託管模型的詳細內容。更多資訊請關注PHP中文網其他相關文章!