برنامه نویسی

مدیریت مدل های مدیریت نشده در 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
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

مراجع

آیا روش ها یا نکات دیگری برای مدیریت مدل های مدیریت نشده دارید؟ آنها را در نظرات زیر به اشتراک بگذارید!

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دکمه بازگشت به بالا