اختبارات التكامل
درس 2 من 3
2اختبارات التكامل
الصورة الكبيرةدالتك تبني SQL صحيحًا، وقاعدة البيانات تعمل، لكن اسم العمود في الكود created وفي الجدول created_at. لا اختبار وحدوي سيلتقط هذا. اختبار التكامل يشغّل القطعتين معًا.
ماذا تشاهد في الرسم: اختبار تكامل: كل الأجزاء حقيقية، والبيئة تُجهّز وتُنظّف حول كل اختبار.
خارطة هذا الجزء
المفاهيم بالترتيب، اضغط أيًّا منها للقفز إليه:
طريقان إلى نفس الفكرة
اختبرت المحرك وحده ونجح، واختبرت العجلات وحدها ونجحت. لكن هل السيارة تمشي؟ اختبار التكامل هو أن تركّب الأجزاء وتقود السيارة في الموقف قبل الطريق.
هرم الاختبارات: كثير من الوحدوية (سريعة)، أقل من التكامل (قاعدة، HTTP)، وقليل من الشاملة (e2e عبر المتصفح). للتكامل استخدم نفس نوع قاعدة الإنتاج (Postgres في Docker أو Testcontainers)، فـ SQLite قد يقبل ما يرفضه Postgres. العزل: معاملة تُلغى بعد كل اختبار، أو قاعدة جديدة لكل جلسة. لواجهات HTTP: TestClient في FastAPI أو app.test_client() في Flask أو supertest في Node، دون شبكة حقيقية. الخدمات الخارجية (الدفع) تُستبدل بخادم وهمي أو بيئة sandbox.
قبل أن تبدأ
🧪الاختبارات الوحدوية
الدرس السابق.
🗄️SQL
تكتب INSERT وSELECT.
الفكرة الجوهرية
1الكود مع قاعدة بيانات حقيقية
هنا قاعدة SQLite في الذاكرة تُنشأ نظيفة لكل اختبار. الاختبار يمرّ عبر الكود والقاعدة معًا:
import sqlite3
SCHEMA = "CREATE TABLE orders (id INTEGER PRIMARY KEY, item TEXT NOT NULL, qty INTEGER CHECK (qty > 0))"
def place_order(db, item, qty):
cur = db.execute("INSERT INTO orders (item, qty) VALUES (?, ?)", (item, qty))
return cur.lastrowid
def orders_for(db, item):
return db.execute("SELECT id, qty FROM orders WHERE item = ?", (item,)).fetchall()
def fresh_db():
db = sqlite3.connect(":memory:")
db.execute(SCHEMA)
return db
db = fresh_db()
place_order(db, "latte", 2)
place_order(db, "latte", 1)
assert orders_for(db, "latte") == [(1, 2), (2, 1)]
print("insert + select: ok")
db = fresh_db()
try:
place_order(db, "latte", 0)
except sqlite3.IntegrityError as e:
print("constraint enforced:", e)2اختبار واجهة HTTP كاملة
عميل الاختبار يرسل طلبات للتطبيق مباشرة دون شبكة. تتحقق من كود الحالة والجسم، ثم من القاعدة:
from fastapi.testclient import TestClient
from app import app, get_db
import pytest
@pytest.fixture
def client(tmp_path):
test_db = make_db(tmp_path / "test.db") # fresh database per test
app.dependency_overrides[get_db] = lambda: test_db
yield TestClient(app)
app.dependency_overrides.clear()
def test_create_and_read_order(client):
r = client.post("/orders", json={"item": "latte", "qty": 2})
assert r.status_code == 201
order_id = r.json()["id"]
assert client.get(f"/orders/{order_id}").json()["qty"] == 2
def test_rejects_zero_qty(client):
assert client.post("/orders", json={"item": "latte", "qty": 0}).status_code == 4223هرم الاختبارات
القاعدة الواسعة: مئات الاختبارات الوحدوية بالثواني. الوسط: عشرات اختبارات التكامل بالدقائق. القمة: قليل من الاختبارات الشاملة عبر المتصفح (Playwright) لأهم رحلات المستخدم فقط، لأنها أبطأ وأكثر هشاشة.
docker run --rm -p 5433:5432 -e POSTGRES_PASSWORD=test postgres:17، ووجّه إعدادات الاختبار له.مثال محلول
المسألة: كل الاختبارات الوحدوية خضراء، والإنتاج يرد 500 عند إنشاء طلب. التحليل: الترحيل أضاف عمود branch_id NOT NULL، والكود لا يرسله. الاختبارات الوحدوية تستخدم mock للقاعدة فلم تلاحظ. الحل: اختبار تكامل يشغّل الترحيلات على قاعدة حقيقية ثم ينشئ طلبًا. فشل فورًا، ثم نجح بعد إضافة الحقل.
خرافة مقابل حقيقة
| الخرافة | الحقيقة |
|---|---|
| اختبارات التكامل تغني عن الوحدوية. | أبطأ وتحدد المشكلة بدقة أقل. تحتاج الاثنين. |
| SQLite في الاختبار يكفي دائمًا. | يختلف عن Postgres في الأنواع والقيود. استخدم نفس قاعدة الإنتاج. |
اختبر فهمك
ما الذي يلتقطه اختبار التكامل ولا يلتقطه الوحدوي؟
يجمع القطع الحقيقية فيكشف ما بينها.
لماذا تبدأ كل اختبار بقاعدة نظيفة؟
العزل يجعل الترتيب لا يهم والفشل قابلًا للتكرار.
أين تقع اختبارات المتصفح الشاملة في الهرم؟
بطيئة وهشة، فتُحفظ للأهم.
بطاقات مراجعة سريعة
تحقق من فهمك
كيف تتعامل مع بوابة الدفع في الاختبار؟
بخادم وهمي أو بيئة sandbox من المزوّد، لا بالحقيقية.
اختبار ينجح وحده ويفشل مع الباقي. السبب المرجح؟
حالة مشتركة لم تُنظّف بين الاختبارات.
لماذا لا تجعل كل الاختبارات شاملة عبر المتصفح؟
بطيئة، هشة، وعند الفشل لا تحدد مكان الخطأ.
مصادر هذا الدرس
مرتّبة بالنوع. ابدأ بالتوثيق الرسمي إذا تبي المرجع الدقيق، وبالمقال أو الفيديو إذا تبي الشرح أولًا.
توثيق رسمي2
خلّصت الدرس؟
سجّل الدخول ليُحفظ تقدّمك.