الاختبار في Java: من الاختبارات الوحدوية إلى الاختبارات الشاملة
الاختبار عالي الجودة هو أساس البرمجيات الموثوقة. في عالم Java، يوجد هرم اختبار راسخ يتضمن ثلاثة مستويات رئيسية: unit (الاختبارات الوحدوية)، integration (الاختبارات التكاملية) و e2e (الاختبارات الشاملة). في هذه المقالة، سنشرح كل مستوى منها، ونقدم أمثلة عملية بلغة Java، ونشرح كيفية بناء استراتيجية اختبار صحيحة في مشروعك.
1. Unit-الاختبار الوحدوي: أساس الهرم
تختبر الاختبارات الوحدوية المكونات الفردية للبرنامج بشكل معزول - عادةً ما تكون فئة أو طريقة واحدة. يتم تنفيذها بسرعة، ولا تتطلب تبعيات خارجية (قاعدة بيانات، API)، ويجب أن تغطي معظم منطق الأعمال.
أدوات الاختبارات الوحدوية في Java
- JUnit 5 — الإطار القياسي لكتابة الاختبارات.
- Mockito — مكتبة لإنشاء الكائنات الوهمية (mock objects).
- AssertJ — تأكيدات fluent للتحقق القابل للقراءة.
مثال اختبار وحدوي باستخدام JUnit 5 و Mockito
لنفترض أن لدينا خدمة OrderService تعتمد على PaymentGateway. نريد اختبار منطق حساب الخصم دون استدعاء بوابة الدفع الحقيقية.
// الفئة المراد اختبارها
public class OrderService {
private final PaymentGateway paymentGateway;
public OrderService(PaymentGateway paymentGateway) {
this.paymentGateway = paymentGateway;
}
public double calculateDiscount(double amount) {
if (amount > 1000) {
return amount * 0.1; // خصم 10%
}
return 0;
}
}
// الاختبار الوحدوي
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import static org.junit.jupiter.api.Assertions.assertEquals;
@ExtendWith(MockitoExtension.class)
public class OrderServiceTest {
@Mock
private PaymentGateway paymentGateway;
@InjectMocks
private OrderService orderService;
@Test
public void testCalculateDiscount_AmountAbove1000_Returns10Percent() {
double result = orderService.calculateDiscount(1500);
assertEquals(150.0, result, 0.001);
}
@Test
public void testCalculateDiscount_AmountBelow1000_ReturnsZero() {
double result = orderService.calculateDiscount(500);
assertEquals(0.0, result);
}
}
أفضل الممارسات: استخدم @BeforeEach لتهيئة البيانات المشتركة، وتجنب اختبار الطرق الخاصة مباشرة، واتبع قاعدة "فحص واحد لكل اختبار".
2. الاختبار التكاملي: التحقق من التفاعل
تختبر الاختبارات التكاملية كيفية عمل عدة وحدات معًا - على سبيل المثال، تفاعل الخدمة مع قاعدة البيانات، أو قوائم الرسائل، أو واجهات API الخارجية. على عكس الاختبارات الوحدوية، يتم هنا استخدام التبعيات الحقيقية أو in-memory.
أدوات الاختبارات التكاملية
- Spring Boot Test — لاختبار تطبيقات Spring.
- Testcontainers — لتشغيل حاويات Docker (قاعدة بيانات، Kafka).
- H2 Database — قاعدة بيانات in-memory للاختبارات السريعة.
مثال اختبار تكاملي باستخدام Spring Boot
نختبر REST-controller مع اتصال حقيقي بقاعدة البيانات (نستخدم H2 في الاختبار).
// المتحكم (Controller)
@RestController
@RequestMapping("/api/users")
public class UserController {
private final UserRepository userRepository;
public UserController(UserRepository userRepository) {
this.userRepository = userRepository;
}
@GetMapping("/{id}")
public User getUser(@PathVariable Long id) {
return userRepository.findById(id)
.orElseThrow(() -> new Runti