الاختبارات و TDD
اختبار الخدمات المصغرة
اختبار الخدمات المصغرة
يقدم اختبار بنية الخدمات المصغرة تحديات فريدة. يجب أن تتواصل الخدمات بشكل موثوق، ويجب الحفاظ على العقود، وإدارة التعقيد الموزع. يستكشف هذا الدرس استراتيجيات اختبار الخدمات المصغرة.
هرم اختبار الخدمات المصغرة
مستويات الاختبار:
- اختبارات الوحدة: اختبار مكونات الخدمة الفردية
- اختبارات التكامل: اختبار تفاعلات الخدمة
- اختبارات العقود: التحقق من عقود API
- اختبارات شاملة: اختبار رحلات المستخدم الكاملة
اختبار العقود مع Pact
// اختبار المستهلك - خدمة الطلبات
class UserServiceContractTest extends TestCase
{
public function test_get_user_contract()
{
$request = new ConsumerRequest();
$request->setMethod('GET')
->setPath('/api/users/123');
$response = new ProviderResponse();
$response->setStatus(200)
->setBody([
'id' => 123,
'name' => 'John Doe',
'email' => 'john@example.com'
]);
$this->builder
->given('User 123 exists')
->uponReceiving('Request for user 123')
->with($request)
->willRespondWith($response);
$user = $this->userService->getUser(123);
$this->assertEquals('John Doe', $user['name']);
}
}
محاكاة الخدمة الافتراضية
// محاكاة استجابات الخدمة الخارجية
class PaymentServiceMock
{
public static function mockSuccessfulPayment()
{
Http::fake([
'payment-service.com/api/charge' => Http::response([
'transaction_id' => 'txn_123',
'status' => 'success',
'amount' => 100.00
], 200)
]);
}
public static function mockFailedPayment()
{
Http::fake([
'payment-service.com/api/charge' => Http::response([
'error' => 'Insufficient funds'
], 402)
]);
}
}
اختبار تواصل الخدمات
// اختبار اتصال HTTP بين الخدمات
public function test_order_service_calls_user_service()
{
Http::fake([
'user-service.com/api/users/*' => Http::response([
'id' => 1,
'name' => 'Test User'
])
]);
$order = Order::factory()->create();
$result = $this->orderService->processOrder($order);
Http::assertSent(function ($request) {
return $request->url() == 'http://user-service.com/api/users/1';
});
}
اختبار قوائم انتظار الرسائل
// اختبار نشر الأحداث
public function test_order_created_event_is_published()
{
Event::fake([OrderCreated::class]);
$order = $this->orderService->createOrder([
'user_id' => 1,
'total' => 100
]);
Event::assertDispatched(OrderCreated::class, function ($event) use ($order) {
return $event->order->id === $order->id;
});
}
اختبار قواطع الدوائر
// اختبار نمط قاطع الدائرة
public function test_circuit_breaker_opens_on_failures()
{
Http::fake([
'external-service.com/*' => Http::response([], 500)
]);
// تحفيز إخفاقات متعددة
for ($i = 0; $i < 5; $i++) {
try {
$this->service->callExternalApi();
} catch (Exception $e) {
// إخفاقات متوقعة
}
}
// يجب أن تكون الدائرة مفتوحة
$this->assertTrue($this->service->isCircuitOpen());
// يجب أن تفشل المكالمة التالية بسرعة
$this->expectException(CircuitBreakerOpenException::class);
$this->service->callExternalApi();
}
اختبار اكتشاف الخدمات
// اختبار سجل الخدمات
public function test_service_discovery()
{
$registry = new ServiceRegistry();
$registry->register('user-service', 'http://localhost:8001');
$registry->register('order-service', 'http://localhost:8002');
$userServiceUrl = $registry->discover('user-service');
$this->assertEquals('http://localhost:8001', $userServiceUrl);
}
نصائح اختبار الخدمات المصغرة:
- استخدم اختبار العقود لمنع مشاكل التكامل
- محاكاة الخدمات الخارجية في اختبارات الوحدة
- اختبار سيناريوهات الفشل والمهلات
- التحقق من آليات إعادة المحاولة
- اختبار تدهور الخدمة بأمان
الأخطاء الشائعة:
- عدم اختبار أعطال الشبكة
- تجاهل الاتساق النهائي
- الاعتماد المفرط على الاختبارات الشاملة
- عدم تعيين إصدارات لعقود API
- إعدادات المهلة المفقودة
تمرين: أنشئ اختبار عقد بين خدمتين. اختبر التواصل الناجح، معالجة الأخطاء، وسيناريوهات المهلة.