يتطلب نمط الاختبار المقترح تكرارًا معياريًا لرمز التطبيق ولا يُظهر اختبار التطبيق مباشرةً.
https://docs.aiohttp.org/en/stable/testing.html#pytest
من المفترض أن أتمكن من تمرير وحدة تطبيقي مباشرةً إلى test_client
لاختبار تطبيقي.
تعرض المستندات إنشاء التطبيق من معالجات أثناء التنقل قبل كل اختبار. تمرير app
الحقيقي مباشرة إلى test_client
يعمل بشكل جيد في المرة الأولى ، ثم يفشل مع "RuntimeError: web.Application تم تهيئته باستخدام حلقة مختلفة".
# handler.py
async def foo():
return 'foo'
# app.py
from aiohttp import web
from .handler import foo
app = web.Application()
app.add_routes([web.get('/foo/', foo)])
# test.py
from .app import app
async def test_foo_status(test_client):
response = await client.get('/foo/')
assert response.status == 200
async def test_foo_body(test_client):
response = await client.get('/foo/')
body = await response.text()
assert body == 'foo'
لقد اخترقت المشكلة في الوقت الحالي من خلال إلقاء نظرة خاطفة على كود المصدر وتحديد سبب الخطأ.
if self._loop is not None and self._loop is not loop:
raise RuntimeError(
"web.Application instance initialized with different loop")
https://github.com/aio-libs/aiohttp/blob/e561eaa/aiohttp/web_app.py#L134
ليس من الواضح على الفور لماذا هذا الرمز ضروري. لم أجد أي سياق في تاريخ بوابة. يبدو أن تعيين app._loop = None
في طريقة التنظيف التجريبية الخاصة بي لتجنب المشكلة دون أي آثار جانبية سلبية. هل هذا الرمز ضروري بالفعل؟ هل يمكن دمج هذا الإصلاح في test_client
؟
Application
هو كائن ذو حالة ، يجب إعادة إنشائه لكل اختبار من مجموعة اختبار الوحدة.
يجب أن يكون عمر التطبيق أقصر من عمر حلقة الحدث.
تلميح: استبدل app.app
بـ async def app.make_app()
coroutine الذي يُرجع تطبيقًا جديدًا في كل مكالمة.
أضف def make_app()
إلى app.py
؟ منطقي.
تروّج FWIW tornado لنمط make_app()
في أول مثال لها. لا أعتقد أن الاستهزاء بالتطبيق في ملف الاختبار هو نمط جيد للمستندات للترويج له.
بصراحة لا أعتقد أن الاستهزاء بأي عنصر aiohttp
هو نمط جيد
تم قفل سلسلة الرسائل هذه تلقائيًا نظرًا لعدم وجود أي نشاط حديث بعد إغلاقه. الرجاء فتح [إصدار جديد] للأخطاء ذات الصلة.
إذا كنت تشعر أن هناك نقاطًا مهمة تم تناولها في هذه المناقشة ، فيرجى تضمين هذه الأفكار في [العدد الجديد].
التعليق الأكثر فائدة
Application
هو كائن ذو حالة ، يجب إعادة إنشائه لكل اختبار من مجموعة اختبار الوحدة.يجب أن يكون عمر التطبيق أقصر من عمر حلقة الحدث.
تلميح: استبدل
app.app
بـasync def app.make_app()
coroutine الذي يُرجع تطبيقًا جديدًا في كل مكالمة.