مدیریت مدل های مدیریت نشده در Pytest-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
توجه: برای اینکه این روش کار کند، باید یک را اضافه کنید --no-migrations
گزینه ای برای تنظیمات pytest شما (یا pytest.ini)
مرجع: سرریز پشته
جوانب مثبت:
معایب:
- آزمایش مهاجرت را رد میکند، که میتواند باعث ایجاد مشکلاتی در زمانی که چند برنامهنویس روی یک پروژه کار میکنند.
روش 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
انجام تست های تراکنش با مدل های مدیریت نشده
از آنجایی که تستهای تراکنش فقط مدلهای مدیریتشده را کوتاه میکنند، میتوانیم مدلهای مدیریتنشده را تغییر دهیم تا در طول اجرای آزمایشی مدیریت شوند. این تضمین می کند که آنها در برش قرار می گیرند:
def setup_unmanaged_models(connection, schema_editor):
# As before
for model in unmanaged_models:
# As before
model._meta.managed = True # Hack: Mark as managed
اجتناب از تراکنش=درست با on_commit Hooks (در صورت امکان)
در سناریوهای مربوط به on_commit
با استفاده از فیکسچر، میتوانید با گرفتن و اجرای مستقیم callbacks on_commit از استفاده از تستهای تراکنش اجتناب کنید. django_capture_on_commit_callbacks
از pytest-django(>= v.4.4)
:
@pytest.mark.django_db
def mytest(django_capture_on_commit_callbacks):
with django_capture_on_commit_callbacks(execute=True):
# Test logic here
# `on_commit` hooks will execute immediately
مراجع
آیا روش ها یا نکات دیگری برای مدیریت مدل های مدیریت نشده دارید؟ آنها را در نظرات زیر به اشتراک بگذارید!