FastAPI / المتوسط: تكامل التطبيق والأمن / الدرس 8
الاختبارات وعزل التبعيات
تحقق من السلوك العام بتطبيقات معزولة وتبعيات مضبوطة وعميل اختبار مناسب.
في هذه الصفحة
أهداف الدرس
- اشرح افتراضات وحدود موضوع «الاختبارات وعزل التبعيات».
- فسر المثالين الكاملين وعلل المخرجات الملاحظة.
- شخص الإخفاقات وطبق الحلول المشروحة مع وضوح ملكية الهوية والحالة ودورة الحياة.
اختبار السلوك عبر حد تطبيق حقيقي
يرسل الاختبار طلبا ممثلا ويفحص الحالة والتمثيل والأثر لا استدعاء مساعد فقط. اختبر العمل نقيا والتوصيل داخليا. يبدل المثال مزودا اصطناعيا ويفحص ثم يزيله، دون خادم؛ فلا يثبت الوكيل وTLS والعمال والقاعدة والخارج، ووضح النطاق.
from typing import Annotated
from fastapi import Depends, FastAPI
from fastapi.testclient import TestClient
def source(): return "original-lab-value"
app = FastAPI()
@app.get("/value")
def value(text: Annotated[str, Depends(source)]): return {"value": text}
with TestClient(app) as client:
app.dependency_overrides[source] = lambda: "fixed-lab-value"
try:
response = client.get("/value")
assert response.status_code == 200
print(response.json())
finally:
app.dependency_overrides.clear()
print(client.get("/value").json())
{'value': 'fixed-lab-value'}
{'value': 'original-lab-value'}
يغير البديل المزود فقط ويزال في finally؛ ويثبت الطلب التالي الاستعادة.
إعطاء تجهيزات الاختبار ملكية صريحة
أنشئ تطبيقا وحالة معزولين ونظف في finally أوسياق حتى يفشل التحقق. تربط البدائل بالدالة الأصلية لا المشابهة. تجنب قاعدة المشروع والاعتمادات والأسماء المشتركة. غالبا يفسر تسرب حالة وترتيب وبيئة وحياة فشل الجيران؛ فأصلح الملكية لا الإعادة العمياء.
مطابقة أسلوب العميل للاختبار
يلائم TestClient المتزامن ويستخدم AsyncClient وASGITransport عند الحاجة لـawait. يستدعي المثال run عند مدخل الملف فقط، ولا يدير ASGITransport الحياة تلقائيا؛ فيلزم ترتيب صريح إن وجدت موارد، ولا توجد هنا. لا تخلط الحلقات أوعمر العميل لمجرد توفر عام.
import asyncio
from fastapi import FastAPI
from httpx import ASGITransport, AsyncClient
app = FastAPI()
@app.get("/health")
async def health(): return {"ok": True}
async def main():
transport = ASGITransport(app=app)
async with AsyncClient(transport=transport, base_url="http://lab.invalid") as client:
response = await client.get("/health")
assert response.status_code == 200
print(response.json())
asyncio.run(main())
{'ok': True}
الاسم سياق رابط فقط ويرسل النقل للتطبيق المحلي بلا DNS أوشبكة، ولا مورد حياة هنا.
فحص الفشل وحدود الأمن
أدرج الباطل والغياب والمنع والترشيح والتنظيف، واستفد من رفع عيب الخادم الافتراضي أوخيار مقصود للرد العام. افحص الرمز والموقع لا المكدس. اضبط السيناريو بالبديل دون حذف السياسة المقصودة؛ فاحقن فاعلا اصطناعيا ونفذ الملكية الحقيقية لا مسارا خياليا.
جعل الدليل قابلا للتكرار ومحدودا
سجل الإصدارات وتجنب نوم عشوائي أوزمن شبكة. استخدم نتيجة وحالة وجدولة مضبوطة، ولا تثبت التغطية جودة التحقق؛ فاسأل عن رجوع محتمل. السكربتات كاملة داخلية بلا خادم أوتخزين مهيأ، وتحتاج الضمانات الخارجية إذنا واختبارات أخرى لا ادعاء إنتاج.
الأخطاء الشائعة وإصلاحها
يستخدم الاختبار اعتمادية المشروع الحقيقية
- لماذا يحدث؟
- اختيرت دالة خاطئة أوغاب البديل.
- كيف تصلحه؟
- احقن آمنا وتحقق من المفتاح.
- كيف تتجنب تكراره؟
- استخدم عزلا وسياسة بلا خارج.
تغفل اختبارات async حالة البدء
- لماذا يحدث؟
- افتُرض إدارة النقل للحياة.
- كيف تصلحه؟
- أدر الحياة صراحة للتطبيق ذي الموارد.
- كيف تتجنب تكراره؟
- اختبر الأخذ والتنظيف حول العميل.
تنجح بعد تعطيل الإذن الحقيقي
- لماذا يحدث؟
- استبدل البديل السياسة المقصودة.
- كيف تصلحه؟
- بدل المدخل واحفظ السياسة.
- كيف تتجنب تكراره؟
- أدرج غير المالك والمنع.
اختبر فهمك
1. أي تبعية تبدل لاختبار ملكية مورد؟
اعرض الحل المشروح
بدل محقق الهوية أوالمستودع مع بقاء الملكية، وافحص المالك والآخر. السماح الدائم يختبر البديل لا يحمي العقد.
2. لماذا يضعف نوم عشوائي انتظار الخلفية؟
اعرض الحل المشروح
يؤخر دون إثبات وقد يفشل بجدولة أخرى. استخدم إشارة أونتيجة مملوكة بالحد المدعوم ولا تدع ضمان توزيع من الذاكرة.
أهم ما تعلمته
- يرسل الاختبار طلبا ممثلا ويفحص الحالة والتمثيل والأثر لا استدعاء مساعد فقط.
- يلائم TestClient المتزامن ويستخدم AsyncClient وASGITransport عند الحاجة لـawait.
- سجل الإصدارات وتجنب نوم عشوائي أوزمن شبكة.