Pytest-django: كيفية استخدام علامة django_db في تجهيزات الجلسة؟

تم إنشاؤها على ١٤ سبتمبر ٢٠١٧  ·  15تعليقات  ·  مصدر: pytest-dev/pytest-django

لدي موقف أحتاج فيه إلى تحميل تركيبات ديسيبل ضخمة تم إنشاؤها بواسطة وظيفة. التثبيت مطلوب في جميع اختبارات API. لذلك قمت بعمل جلسة ثابتة بسعر conftest.py والذي سيفعل ذلك. لكن المشكلة هي أن pytest يطرح بعد الاستثناء بالرغم من أنني قمت بتمييز django_db :

E Failed: Database access not allowed, use the "django_db" mark to enable it.
يوجد أدناه مقتطف الشفرة الخاص بي.

from permission.helpers import update_permissions

pytestmark = [
        pytest.mark.django_db(transaction = True),]

@pytest.fixture(scope="session", autouse = True)
def permission(request):
        load_time_consuming_db_fixture()
db-configuration enhancement

التعليق الأكثر فائدة

لقد كانت هذه أكبر نقطة ألم بالنسبة لي قادمة من الاختبارات المستندة إلى الفصل في Django ، إلى pytest-django - في Django نستخدم setUpTestData لتشغيل عمليات DB باهظة الثمن مرة واحدة (ما يعادل تركيبات pytest ذات نطاق الجلسة) ، ثم هناك حيلة ماكرة لتشغيل obj.refresh_from_db() في setUp لتحديث مراجع الفصل.

حتى إذا كنت أقوم بإنشاء مثيل نموذج قاعدة بيانات واحد فقط ، وقمت بإعادة تحميله في كل TC ، فسيكون هذا دائمًا أسرع من الإنشاء في كل حالة اختبار.

سيكون من الرائع لو تمكنا من الحصول على التركيبات ذات نطاق الجلسة من دمج pytest-tipsi-django المنبع ، إذا كان هذا ممكنًا ؛ استغرق الأمر بعض البحث للعثور على هذه المشكلة والحل.

ال 15 كومينتر

ludbek فقدنا أيضًا هذه الميزة وأنشأنا مكونًا إضافيًا لهذه الميزة:
https://github.com/tipsi/pytest-tipsi-django (الاستخدام: https://github.com/tipsi/pytest-tipsi-django/blob/master/test_django_plugin/app/tests/test_transactions.py)
بالتزامن مع:
https://github.com/tipsi/pytest-tipsi-testing
يمنحك القدرة على تداخل المعاملات وتصحيح أمر التنفيذ / الإغلاق.

cybergrind شكرا على الرد. سوف أتحقق من ذلك بالتأكيد وأعلمك كيف سارت الأمور.

لقد كانت هذه أكبر نقطة ألم بالنسبة لي قادمة من الاختبارات المستندة إلى الفصل في Django ، إلى pytest-django - في Django نستخدم setUpTestData لتشغيل عمليات DB باهظة الثمن مرة واحدة (ما يعادل تركيبات pytest ذات نطاق الجلسة) ، ثم هناك حيلة ماكرة لتشغيل obj.refresh_from_db() في setUp لتحديث مراجع الفصل.

حتى إذا كنت أقوم بإنشاء مثيل نموذج قاعدة بيانات واحد فقط ، وقمت بإعادة تحميله في كل TC ، فسيكون هذا دائمًا أسرع من الإنشاء في كل حالة اختبار.

سيكون من الرائع لو تمكنا من الحصول على التركيبات ذات نطاق الجلسة من دمج pytest-tipsi-django المنبع ، إذا كان هذا ممكنًا ؛ استغرق الأمر بعض البحث للعثور على هذه المشكلة والحل.

هلاpaultiplady

لست متأكدًا من أن هذا الأسلوب من pytest-tipsi-djanjo يناسب نموذج الاختبار المعتاد لـ pytest . الاختلاف الأكثر وضوحًا هو التشطيب على التركيبات: حاليًا pytest لا تنتهي صراحةً من التركيبات غير الضرورية بنطاق أوسع. لذلك تحتاج إلى إنهاء المعاملات صراحة بترتيب معين وبشكل عام ، قد يتسبب هذا في تأثيرات مختلفة جدًا (حاليًا pytest قد يبقي التركيبات نشطة حتى إذا كان الاختبار النشط وتركيباته لا تتطلب ذلك على الإطلاق).

اضطررنا إلى تغيير الاختبارات في مشروعنا إلى هذا النهج لأننا نحتاج إلى اختبار بعض السيناريوهات الكبيرة في بعض الأحيان وقمنا باستبدال إدارة المعاملات اليدوية الحالية في اختبارات ضخمة بتركيبات أفضل قليلاً ، لكنها لا تزال تتطلب الاهتمام باختبارات الطلب.

يمكنني الآن رؤية حل واحد فقط لذلك: وضع نوع من الأسئلة الشائعة في الوثائق.

شكرًا على التفاصيل الإضافيةcybergrind. لقد تعمقت في هذا الأمر أكثر قليلاً ، لكن الوقت قد نفد منه لليوم - وهنا ما يجب علي فعله ، سأقدر التحقق من صحة ما إذا كان هذا النهج مفيدًا أم لا ، بما أنني ليس مألوفًا مع الأجزاء الداخلية pytest.

كما أنني لا أفهم ما تقصده بعبارة "لا ينهي pytest صراحة التركيبات غير الضرورية بنطاق أوسع" ، هل يمكنك التوسع في ذلك قليلاً من فضلك؟ هل هذا يشير إلى المصغرين؟ قد يؤثر ذلك على ما كتبته أدناه.

يستخدم المكون الإضافي pytest-django علامة django_db ، والتي يتم التعامل معها في _django_db_marker في plugin.py (https://github.com/pytest-dev/pytest-django/blob/master/pytest_django/plugin.py # L375) ، الذي يستدعي الوظيفة db fixture (https://github.com/pytest-dev/pytest-django/blob/master/pytest_django/fixture.py#L142). تقوم هذه الأداة بإنشاء مثيل لـ Django TestCase ، وتستدعي وظيفتها _pre_setup (وتضع في قائمة _post_teardown ).

يمكنني رؤية خيارين:

أتساءل عما إذا كان بإمكاننا تمديد _django_db_marker للقيام اختياريًا بفصل- أو جلسة-
إعداد النطاق أيضًا ، والذي سيفعل نفس الشيء مثل db ، لكن استدعاء ما يعادل cls.setUpTestData أو وظيفة تم تمريرها في mark kwargs بدلاً من ذلك.

بالنسبة إلى نطاق الفصل ، وأنا أفترض بالنسبة إلى نطاق الجلسة أيضًا ، أن السلوك المتوقع سيكون التراجع عن قاعدة البيانات بعد ذلك ، لذلك نحتاج أساسًا إلى تركيبات محددة النطاق تعمل بالترتيب الصحيح ، وأن يقوم كل منها بإعداد ذريته الخاصة عملية تجارية. أعتقد أن هذا يعني أن هذا يجب أن يكون تعديلاً للثروة db ، بدلاً من تركيبات منفصلة تعمل بجانبها.

بهذه الطريقة سنقوم بتشغيل أي إعداد محدد على مستوى الفصل / الجلسة بشكل صحيح ، وسيتم استدعاء هذا الإعداد مرة واحدة لكل فصل / جلسة. أعتقد أنه يلزم إجراء تعديل على العلامة نفسها لأنك إذا قمت للتو بإعداد وظيفة نطاق الجلسة والتي تعمل يدويًا على تشغيل django_db_blocker.unblock() ، يبدو أن هذا يحدث بعد أن قامت علامة django_db بإعداد المعاملة الأولى.

قد يبدو هذا مشابهًا لما يلي (في plugin.py _django_db_marker() ):

    if marker:
        if marker.session_db:
            getfixturevalue(request, 'db_session')

        if marker.class_db:
            getfixturevalue(request, 'db_class')

        validate_django_db(marker)
        if marker.transaction:
            getfixturevalue(request, 'transactional_db')
        else:
            getfixturevalue(request, 'db')

هل هذا حديث مجنون ، أم أن هذا الموضوع يستحق المزيد من الاستكشاف؟

بخصوص الإنهاء: https://github.com/tipsi/pytest-tipsi-testing/blob/master/tests/test_finalization.py

لا يعمل هذا الاختبار بدون إنهاء صريح ، مثل تركيبات قاعدة البيانات غير الوظيفية. وهذا يتعلق بتنفيذ pytest ، لذلك ليس هناك ما يمكن فعله في pytest-django لإصلاحه.

تكرار # 388 و # 33

شكرا ختاما.

33 مغلق ، والرقم 388 لا يحتوي على مناقشة ذات مغزى (بخلاف هذا). يبدو من الغريب إغلاق هذا blueyed ، إذا كان هناك أي شيء أقترح إغلاق # 388 وجعل هذا الخيار الأساسي لهذه المشكلة.

👍 شكرا!

كما أنني أقدر كثيرا هذه الوظيفة.

تضمين التغريدة
كم الثمن؟ يكفي لتحقيق ذلك بنفسك؟ ؛)

على أي حال ، فإن المشكلة الرئيسية / الأساسية هنا (من التعليق الأصلي) هي بالفعل إعادة تعيين قاعدة البيانات أثناء الاختبارات ، لذلك لا توجد طريقة تافهة للحصول على جلسة محددة النطاق من هذا القبيل.

ما قد ينجح رغم ذلك هو شيء ما على طول:

@pytest.fixture(scope="session")
def django_db_setup(django_db_setup, django_db_blocker):
    with django_db_blocker.unblock():
        with transaction.atomic():  # XXX: could/should use `TestCase_enter_atomics` for multiple dbs
            load_time_consuming_db_fixture()
            yield

الفكرة هي لف كل شيء في كتلة ذرية إضافية. هذا لم يتم اختباره ، وقد تحتاج إلى استخدام TransactionTestCase لهذا الغرض.

تضمين التغريدة
يبدو تعليقك جيدًا - أي أنه يستحق المزيد من الاستكشاف AFAICS (انظر أيضًا تعليقي السابق).

blueyed نحن نستخدم مثل هذا النهج لأكثر من عام (نلف كل شيء في كتلة ذرية إضافية) وهو يعمل بشكل جيد.
ولكن لا يمكنك فقط تسجيل شيء من هذا القبيل لأن pytest ليس لديه المحدد حيث سيتم إغلاق مستوى الجلسة (وأعلى من الاختبار) لذلك سيتطلب تتبع تبعيات معاملات db بغض النظر عن أنها تتطلب بعضها البعض أم لا .
لذلك تحتاج إلى تتبع مكدس المعاملات بشكل صريح وإغلاق المعاملات المتداخلة قبل الاختبار التالي. يمكن القيام به بهذه الطريقة: https://github.com/tipsi/pytest-tipsi-django/blob/master/pytest_tipsi_django/django_fixture.py#L46

آسف أريد التوضيح لأنني أعتقد أنني أواجه نفس المشكلة:

إذا كنت أرغب في إنشاء تركيبات تعتمد على إنشاء كائن ديسيبل جديد ، فقد اعتقدت أنه يمكنني القيام بذلك

@pytest.mark.django_db(transaction=True)
@pytest.fixture(scope="session")
def object():
    object = Object.create_object(params)
    yield object
    // or alternatively
    object = mixer.blend('myObject')
    yield object

ومع ذلك ، أتلقى الخطأ التالي عند تشغيل حالة الاختبار: Database access not allowed, use the "django_db" mark, or the "db" or "transactional_db" fixtures to enable it.

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات