जावा में परीक्षण: यूनिट, इंटीग्रेशन, E2E — उन्नत स्तर
\n\nआधुनिक जावा-डेवलपमेंट में, परीक्षण केवल एक औपचारिकता नहीं है, बल्कि एक मौलिक अभ्यास है जो कोड की स्थिरता और पूर्वानुमानशीलता सुनिश्चित करता है। बुनियादी परीक्षण, जैसे Assert.assertEquals के साथ सरल @Test, ने लंबे समय से जटिल बहु-स्तरीय रणनीतियों को रास्ता दिया है। इस लेख में, हम परीक्षण पिरामिड के प्रत्येक स्तर के लिए उन्नत तकनीकों पर चर्चा करेंगे: यूनिट, इंटीग्रेशन और एंड-टू-एंड (E2E)। आप सीखेंगे कि कैसे रखरखाव योग्य, तेज़ और विश्वसनीय परीक्षण लिखें जो आपके कोड को एक अच्छी तरह से ट्यून किए गए तंत्र में बदल देंगे।
1. उन्नत यूनिट-परीक्षण: मॉक, स्टब और पैरामीटरीकरण
\n\nयूनिट-परीक्षण कोड के एक पृथक टुकड़े (आमतौर पर एक क्लास या विधि) की जाँच करते हैं। उन्नत स्तर पर, हम सरल परिदृश्यों से जटिल अंतःक्रियाओं और सीमा मामलों की ओर बढ़ते हैं। यहाँ मुख्य उपकरण Mockito लाइब्रेरी है।
\n\n1.1. ArgumentCaptor और जटिल उत्तरों (Answer) का उपयोग
\n\nअक्सर केवल यह जाँचना आवश्यक नहीं होता कि कोई विधि कॉल की गई थी, बल्कि यह भी कि उसे कौन से तर्क दिए गए थे। इसके लिए ArgumentCaptor का उपयोग किया जाता है।
// उदाहरण: जाँच करना कि सेवा को सही संदेश भेजा गया है\n@ExtendWith(MockitoExtension.class)\npublic class NotificationServiceTest {\n @Mock\n private EmailSender emailSender;\n @InjectMocks\n private NotificationService notificationService;\n\n @Test\n void shouldSendEmailWithCorrectContent() {\n // Arrange\n User user = new User("test@example.com", "Test User");\n // Act\n notificationService.sendWelcomeEmail(user);\n // Assert\n ArgumentCaptor<EmailMessage> captor = ArgumentCaptor.forClass(EmailMessage.class);\n verify(emailSender).send(captor.capture());\n EmailMessage capturedMessage = captor.getValue();\n assertEquals("test@example.com", capturedMessage.getTo());\n assertTrue(capturedMessage.getBody().contains("Test User"));\n }\n}\n\nइनपुट डेटा के आधार पर गतिशील रूप से उत्तर बनाने के लिए, Answer इंटरफ़ेस का उपयोग करें:
@Test\nvoid testDynamicResponse() {\n when(dataRepository.findById(anyLong())).thenAnswer(invocation -> {\n Long id = invocation.getArgument(0);\n return new DataEntity(id, "Entity with ID: " + id);\n });\n assertEquals("Entity with ID: 5", dataService.getDataById(5L).getName());\n}\n\n1.2. पैरामीटरीकृत परीक्षण (JUnit 5)
\n\nपैरामीटरीकरण आपको कोड दोहराव से बचते हुए, डेटा के विभिन्न सेटों के साथ एक ही परीक्षण चलाने की अनुमति देता है। JUnit 5 शक्तिशाली एनोटेशन प्रदान करता है, जैसे @CsvSource और @MethodSource।
@ParameterizedTest\n@CsvSource({\n "10, 20, 30",\n "0, 0, 0",\n "-5, 5, 0"\n})\nvoid testSum(int a, int b, int expectedSum) {\n Calculator calculator = new Calculator();\n assertEquals(expectedSum, calculator.add(a, b));\n}\n\n2. इंटीग्रेशन परीक्षण: डेटाबेस और बाहरी सेवाओं के साथ कार्य करना
\n\nइंटीग्रेशन परीक्षण सिस्टम के घटकों के बीच अंतःक्रिया की जाँच करते हैं, उदाहरण के लिए, वास्तविक डेटाबेस या कतारों के साथ। मुख्य चुनौती वातावरण की स्थिति का प्रबंधन करना है। यहाँ Testcontainers मदद करता है।
\n\n2.1. पृथक डेटाबेस के लिए Testcontainers
\n\nTestcontainers परीक्षणों के दौरान आवश्यक सॉफ़्टवेयर (PostgreSQL, Redis, Kafka) के साथ Docker कंटेनरों को ऊपर उठाता है, जिससे स्वच्छता और पुनरुत्पादनशीलता सुनिश्चित होती है।
\n\n@SpringBootTest\n@Testcontainers\nclass UserRepositoryIntegrationTest {\n\n @Container\n static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:15")\n .withDatabaseName("testdb")\n .withUsername("test")\n .withPassword("test");\n\n @DynamicPropertySource\n static void configureProperties(DynamicPropertyR