اختبارات التكامل تأكد من أن أجزاء واجهة برمجة التطبيقات الخاصة بك تعمل معًا بشكل صحيح – المسارات وقاعدة البيانات ومنطق الأعمال – عن طريق تقديم طلبات حقيقية والتحقق من الاستجابات الحقيقية. على عكس اختبارات الوحدة (التي تسخر من كل شيء)، فإن اختبارات التكامل تكتشف الأخطاء عند الحدود. يوضح هذا الدليل كيفية كتابتها بشكل جيد.
📋 Table of Contents
اختبارات الوحدة مقابل التكامل
| الجانب | اختبار الوحدة | اختبار التكامل |
|---|---|---|
| النطاق | دالة واحدة منفردة | أجزاء متعددة معًا (المسار + قاعدة البيانات) |
| التبعيات | سخرية | قاعدة بيانات حقيقية (أو اختبارية) |
| السرعة | سريع جدا | أبطأ (الإدخال/الإخراج الحقيقي) |
| المصيد | أخطاء منطقية | أخطاء التكامل/الأسلاك |
تريد كلاهما – اختبارات الوحدة للمنطق، واختبارات التكامل للتحقق من عمل تدفق الطلب والاستجابة بالكامل.
Node.js: الاختبار باستخدام Supertest
npm install --save-dev jest supertest
// Export your app WITHOUT calling listen() so tests can use it
// app.js
const express = require('express');
const app = express();
app.use(express.json());
app.get('/users/:id', getUser);
app.post('/users', createUser);
module.exports = app; // export the app
// server.js (separate) starts it
const app = require('./app');
app.listen(3000);
// users.test.js
const request = require('supertest');
const app = require('./app');
const db = require('./db');
describe('Users API', () => {
beforeEach(async () => {
await db.reset(); // clean database before each test
});
afterAll(async () => {
await db.close();
});
it('creates a user', async () => {
const res = await request(app)
.post('/users')
.send({ name: 'Alice', email: 'alice@example.com' });
expect(res.status).toBe(201);
expect(res.body).toMatchObject({ name: 'Alice' });
expect(res.body.id).toBeDefined();
});
it('returns 404 for missing user', async () => {
const res = await request(app).get('/users/999');
expect(res.status).toBe(404);
});
it('validates required fields', async () => {
const res = await request(app).post('/users').send({});
expect(res.status).toBe(400);
expect(res.body.error).toBeDefined();
});
});
بايثون: الاختبار باستخدام pytest وTestClient
pip install pytest httpx
# test_users.py (FastAPI example)
import pytest
from fastapi.testclient import TestClient
from app.main import app
from app.database import get_test_db
client = TestClient(app)
@pytest.fixture(autouse=True)
def reset_db():
db = get_test_db()
db.reset()
yield
db.close()
def test_create_user():
response = client.post("/users", json={
"name": "Alice", "email": "alice@example.com"
})
assert response.status_code == 201
data = response.json()
assert data["name"] == "Alice"
assert "id" in data
def test_get_missing_user():
response = client.get("/users/999")
assert response.status_code == 404
def test_validation_error():
response = client.post("/users", json={})
assert response.status_code == 422
استخدام قاعدة بيانات اختبارية
تحتاج اختبارات التكامل إلى قاعدة بيانات (اختبارية) حقيقية — منفصلة عن التطوير والإنتاج:
# Spin up a test database with Docker
docker run -d --name test-db -p 5433:5432 \
-e POSTGRES_DB=testdb -e POSTGRES_PASSWORD=test \
postgres:15-alpine
# Point tests at it via environment
DATABASE_URL=postgresql://postgres:test@localhost:5433/testdb
// Fast reset using transactions (rollback after each test)
beforeEach(async () => {
await db.query('BEGIN');
});
afterEach(async () => {
await db.query('ROLLBACK'); // undo all changes — fast and clean
});
اختبار نقاط النهاية المصادق عليها
describe('Protected routes', () => {
let token;
beforeAll(async () => {
const res = await request(app)
.post('/login')
.send({ email: 'test@example.com', password: 'password' });
token = res.body.accessToken;
});
it('allows access with valid token', async () => {
const res = await request(app)
.get('/protected')
.set('Authorization', `Bearer ${token}`);
expect(res.status).toBe(200);
});
it('rejects without token', async () => {
const res = await request(app).get('/protected');
expect(res.status).toBe(401);
});
});
تشغيل اختبارات التكامل في CI
# GitHub Actions with a service database
jobs:
test:
runs-on: ubuntu-latest
services:
postgres:
image: postgres:15
env:
POSTGRES_DB: testdb
POSTGRES_PASSWORD: test
ports: ['5432:5432']
options: --health-cmd pg_isready --health-interval 10s
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: '20' }
- run: npm ci
- run: npm run test:integration
env:
DATABASE_URL: postgresql://postgres:test@localhost:5432/testdb
أفضل الممارسات
- اختبارات العزلة: يجب أن يكون كل اختبار مستقلاً — قم بإعادة ضبط قاعدة البيانات بين الاختبارات
- اختبار العقد: التحقق من رموز الحالة وشكل الاستجابة وحالات الخطأ
- تغطية مسارات الخطأ: اختبار 400 و401 و404 وفشل التحقق من الصحة، وليس فقط المسار السعيد
- استخدم قاعدة بيانات اختبارية حقيقية: لا تسخر من قاعدة البيانات في اختبارات التكامل
- احتفظ بها بسرعة معقولة: التراجع عن المعاملات أسرع من اقتطاع الجداول
- تشغيل في CI: تكتشف اختبارات التكامل أخطاء الأسلاك التي تفوتها اختبارات الوحدة
الأسئلة المتداولة
س: هل يجب أن أسخر من قاعدة البيانات في اختبارات التكامل؟
ج: لا، النقطة المهمة هي التحقق من التفاعلات الحقيقية، بما في ذلك قاعدة البيانات. استخدم قاعدة بيانات اختبارية منفصلة. الاستهزاء به يحوله إلى اختبار وحدة ويفتقد أخطاء التكامل التي تحاول اكتشافها.
س: كيف يمكنني إجراء اختبارات التكامل بسرعة؟
ج: استخدم التراجع عن المعاملات بين الاختبارات بدلاً من اقتطاع/إعادة إنشاء الجداول. قم بإجراء الاختبارات بالتوازي حيثما تسمح العزلة. استخدم قاعدة بيانات محتواة واحتفظ بها صغيرة.
س: كم عدد اختبارات التكامل التي أحتاجها؟
ج: قم بتغطية المسارات الهامة لكل نقطة نهاية – النجاح، وأخطاء التحقق من الصحة، وفشل المصادقة، والحالات التي لم يتم العثور عليها. تتعامل اختبارات الوحدة مع التفاصيل المنطقية؛ تغطي اختبارات التكامل السلوكيات الرئيسية لكل نقطة نهاية.
س: اختبارات التكامل أو اختبارات E2E؟
ج: تتحقق اختبارات التكامل من طبقة واجهة برمجة التطبيقات (المسارات + قاعدة البيانات). تتحقق اختبارات E2E من التدفق الكامل للمستخدم عبر واجهة المستخدم. كلاهما لهما قيمة — لديهما اختبارات تكامل أكثر من E2E نظرًا لأنهما أسرع وأكثر تركيزًا.
س: كيف يمكنني اختبار استدعاءات واجهة برمجة التطبيقات الخارجية؟
ج: سخر من تلك الاستدعاءات المحددة (لا تريد إجراء اختبارات على خدمات الطرف الثالث) مع الحفاظ على قاعدة البيانات الخاصة بك حقيقية. يسخر من التبعيات الخارجية الحقيقية فقط، وليس قاعدة البيانات الخاصة بك.
الخلاصة
تتحقق اختبارات التكامل من أن واجهة برمجة التطبيقات الخاصة بك تعمل بشكل كامل – المسارات وقاعدة البيانات والمنطق معًا – مما يؤدي إلى اكتشاف أخطاء الأسلاك التي تفشل اختبارات الوحدة في اكتشافها. استخدمSupertest مع Jest (Node.js) أو pytest مع TestClient (Python)، وقم بتوجيههم إلى قاعدة بيانات اختبار حقيقية (إعادة التعيين بين الاختبارات عبر استعادة المعاملة للسرعة)، وتغطية حالات النجاح، وأخطاء التحقق من الصحة، والمصادقة، والمسارات التي لم يتم العثور عليها. قم بتشغيلها في CI باستخدام قاعدة بيانات الخدمة. تمنحك اختبارات التكامل، جنبًا إلى جنب مع اختبارات الوحدة للمنطق، الثقة في أن واجهة برمجة التطبيقات الخاصة بك تعمل فعليًا كما يتوقع العملاء.
🔗 Share this article
✍️ Leave a Comment