الاختبارات
الاختبارات
Section titled “الاختبارات”إطار الاختبار
Section titled “إطار الاختبار”- pytest مع pytest-asyncio
- التغطية مع pytest-cov
كتابة الاختبارات
Section titled “كتابة الاختبارات”import pytestfrom kazma_core.checkpoint import CheckpointManager
@pytest.fixtureasync def manager(tmp_path): m = CheckpointManager(db_path=str(tmp_path / "test.db")) yield m await m.close()
@pytest.mark.asyncioasync def test_save_and_load(manager): state = {"agent_id": "test", "step": 1} await manager.save(state) loaded = await manager.load(agent_id="test") assert loaded["step"] == 1تشغيل الاختبارات
Section titled “تشغيل الاختبارات”pytestpytest --cov=kazma_core --cov-report=htmlpytest -vالبوابات الثابتة
Section titled “البوابات الثابتة”تُشغَّل مجموعتان اختباريتان مع كل التزام عبر pre-commit (انظر
إعداد بيئة التطوير). كلتاهما تعتمد على AST فقط — لا تُقلعان
التطبيق أبدًا، وتستغرقان معًا نحو ثماني ثوانٍ.
pytest tests/test_imports.py tests/test_static_gates.py -qوُجدت لأن كل واحدة منهما تُغلق فئة عيوب اكتُشفت بالبحث النصي (grep) في الشجرة، لا باختبار فاشل:
| البوابة | ما يُفشل البناء |
|---|---|
test_every_product_module_imports | وحدة لم تعد قابلة للاستيراد. وُلدت من حادثة crawl.py: خلّف حذفٌ استيرادًا معلّقًا، ونجح py_compile، فانكسر البحث في الإنتاج عند أول استخدام. |
test_no_dangling_kazma_import_references | مرجع استيراد kazma_* لا يحلّ إلى أي شيء — يلتقط الاستيرادات على مستوى الدوال التي يفوّتها اختبار الدخان. |
test_no_blocking_db_driver_in_async | استدعاء sqlite3.connect متزامن داخل async def. يُثبِّت حلقة الأحداث التي تخدم أيضًا كل تدفقات SSE وWebSocket. أصلِحه بإسقاط async (يُمرِّر FastAPI المعالجات المتزامنة إلى threadpool) أو بالتغليف في asyncio.to_thread. |
test_no_bare_create_task | نتيجة asyncio.create_task(...) مُهمَلة. تحتفظ الحلقة بمرجع ضعيف فقط، لذا قد تُجمَّع المهمّة كنفايات في منتصف تشغيلها — بصمت وبلا أثر رجعي (traceback). استخدم kazma_core.background.spawn_background. |
test_every_registered_tool_has_a_tier | أداة مسجّلة بلا مدخل في TOOL_TIERS. يرفض HITL افتراضيًا كل ما لا يستطيع تصنيفه، فأداة بلا طبقة ستطلب موافقة حتى على قراءة. |
test_no_unfenced_web_tool_output | أداة ويب تعيد نصًا مؤلَّفًا من جهة بعيدة دون سياج «غير موثوق». |
تحمل قائمة السماح في test_no_blocking_db_driver_in_async سلسلة سبب لكل
إعفاء — أضف إعفاءً فقط مشفوعًا بشرح لماذا لا يمكن تفريغ الاستدعاء إلى خيط
منفصل.
مجموعة اختبارات الانحدار لنتائج التدقيق الأمني
Section titled “مجموعة اختبارات الانحدار لنتائج التدقيق الأمني”يحوي tests/test_audit_2026_08_29_regressions.py اختبارًا سلوكيًا واحدًا لكل
نتيجة تدقيق تضمّنت سلوكًا قابلًا للاستغلال — كُتب كلٌّ منها ليفشل ضد الكود
قبل الإصلاح. إذا لمست وسيط المصادقة، أو قناع الإعدادات، أو shell_exec، أو
بوابة HITL، أو نطاق المستأجرين، فشغّله:
pytest tests/test_audit_2026_08_29_regressions.py -qاختبار الوحدات التي أصبحت حزمًا
Section titled “اختبار الوحدات التي أصبحت حزمًا”عدة وحدات «عملاقة» (god modules) سابقًا أصبحت الآن حزمًا خلف واجهات لم
تتغير (routes_direct، sse_chat، i18n، tool_builtins). ولهذا تبعات
على الاختبارات:
- تأكيدات البحث في المصدر يجب أن تستخدم
tests/_module_source.py. تقرأmodule_source(path)ملف.pyأو تسلسل حزمة كاملة في سلسلة واحدة، وmodule_exists(path)هي الحارس المطابق — فاستدعاءpath.exists()المجرد يُرجعFalseلوحدة تحوّلت إلى حزمة، ما يحوّل التأكيد بصمت إلى عملية بلا أثر. - الرقع (monkeypatching) انتقل مع الكود. رُقّ عند النقطة التي تُعرَّف
فيها (مثل
kazma_ui.sse_chat._helpers)، لا على واجهة الحزمة — فرابطةfrom X import yفي وحدة فرعية أخرى لن ترى رقعًا طُبِّق على فضاء أسماء الحزمة.