आपके टेस्ट झूठ क्यों बोलते हैं, और इसे कैसे ठीक करें?
\n\nकल्पना करें: आप C# में एकदम सही कोड लिखते हैं, उसे टेस्ट से कवर करते हैं, हरी टिक जलती है, CI-पाइपलाइन खुश है। आप रिलीज़ करते हैं… और प्रोडक्शन फेल हो जाता है। परिचित लगता है? सबसे अधिक संभावना है, समस्या कोड में नहीं, बल्कि टेस्ट में है। उन्होंने आपके वास्तविक कोड का परीक्षण नहीं किया, बल्कि उसका एक "खिलौना" संस्करण परीक्षण किया, जो डेटाबेस, फ़ाइल सिस्टम या बाहरी API से जुड़ा था।
\n\nC# में गुणवत्तापूर्ण यूनिट टेस्टिंग के दो स्तंभों मॉक-ऑब्जेक्ट और फिक्स्चर की दुनिया में आपका स्वागत है। इनके बिना, आपके टेस्ट नाजुक इंटीग्रेशन जाँच हैं जो वातावरण में थोड़े से बदलाव से टूट जाते हैं। इनके साथ, आपको तेज़, पृथक और विश्वसनीय टेस्ट मिलते हैं जो वास्तव में कोड की रक्षा करते हैं।
\n\nइस लेख में हम समझेंगे: mock, stub और fake में क्या अंतर है, फिक्स्चर को सही तरीके से कैसे सेट करें, और लोकप्रिय लाइब्रेरीज़: Moq, NSubstitute और AutoFixture के साथ लाइव उदाहरण दिखाएंगे। चलिए शुरू करते हैं!
\n\nMock, Stub, Fake — क्या अंतर है? (स्पॉयलर: यह महत्वपूर्ण है)
\n\nकोड लिखने से पहले, आइए शब्दों पर सहमत हों। कई डेवलपर हर चीज़ के लिए "mock" शब्द का उपयोग करते हैं, लेकिन इससे भ्रम होता है। Gerard Meszaros के वर्गीकरण (पुस्तक "xUnit Test Patterns") में स्पष्ट विभाजन है:
\n\n- \n
- Dummy — एक ऑब्जेक्ट जो पास किया जाता है, लेकिन कभी उपयोग नहीं किया जाता। केवल पैरामीटर भरने के लिए आवश्यक है। \n
- Stub — कॉल पर पूर्व-निर्धारित उत्तर प्रदान करता है। आप स्थिति (state verification) की जाँच करते हैं। \n
- Fake — एक कार्यशील लेकिन सरलीकृत कार्यान्वयन (उदाहरण के लिए, वास्तविक DB के बजाय InMemoryRepository)। \n
- Mock — एक ऑब्जेक्ट जो व्यवहार (behavior verification) की जाँच करता है। आप पुष्टि करते हैं कि एक निश्चित विधि को विशिष्ट तर्कों के साथ बुलाया गया था। \n
व्यवहार में, C# में हम अक्सर इंटरैक्शन की जाँच के लिए मॉक-ऑब्जेक्ट (Moq या NSubstitute के माध्यम से) और टेस्ट डेटा के तेज़ जनरेशन के लिए फिक्स्चर (AutoFixture के माध्यम से) का उपयोग करते हैं। लेकिन चलिए क्रम से चलते हैं।
\n\nC# में मॉक-ऑब्जेक्ट: निर्भरताओं को अलग करना
\n\nकल्पना करें कि आपके पास एक सेवा OrderService है, जो ऑर्डर देने पर ईमेल भेजती है और DB में डेटा सहेजती है। इसका "वास्तविक" परीक्षण करने का मतलब है हर बार पत्र भेजना और डेटाबेस में लिखना। यह धीमा, अविश्वसनीय और महंगा है।
समाधान — निर्भरताओं का पृथक्करण। हम वास्तविक ऑब्जेक्ट (EmailSender, DbContext) को मॉक-ऑब्जेक्ट से बदलते हैं और जाँचते हैं कि सेवा सही पैरामीटर के साथ आवश्यक विधियों को कॉल करती है।
\n\nMoq के साथ उदाहरण (सबसे लोकप्रिय लाइब्रेरी)
\n\npublic interface IEmailSender\n{\n void Send(string to, string subject, string body);\n}\n\npublic interface IOrderRepository\n{\n void Save(Order order);\n}\n\npublic class OrderService\n{\n private readonly IEmailSender _emailSender;\n private readonly IOrderRepository _repository;\n\n public OrderService(IEmailSender emailSender, IOrderRepository repository)\n {\n _emailSender = emailSender;\n _repository = repository;\n }\n\n public void PlaceOrder(Order order)\n {\n // बिज़नेस-लॉजिक\n _repository.Save(order);\n _emailSender.Send(order.CustomerEmail, "ऑर्डर की पुष्टि", $"आपका ऑर्डर #{order.Id} दे दिया गया है।");\n }\n}\n\nअब Moq का उपयोग करके एक टेस्ट लिखते हैं:
\n\n[TestFixture]\npublic class OrderServiceTests\n{\n [Test]\n public void PlaceOrder_ShouldSendEmail_WhenOrderIsValid()\n {\n // Arrange\n var mockEmailSender = new Mock<IEmailSender>();\n var mockRepository = new Mock<IOrderRepository>();\n var service = new OrderService(mockEmailSender.Object, mockRepository.Object);\n var order = new Order { Id =