Test Doubles वे वैकल्पिक ऑब्जेक्ट हैं जिनका उपयोग वास्तविक निर्भरताओं के बजाय यूनिट टेस्टिंग में किया जाता है। यह शब्द Gerard Meszaros द्वारा पुस्तक “xUnit Test Patterns” (2007) में Mock, Stub, Fake, Spy और Dummy के लिए एक सामान्य अवधारणा के रूप में प्रस्तुत किया गया था। Martin Fowler (2024) के अनुसार, Test Doubles परीक्षण किए जा रहे घटक को उसके परिवेश से अलग करने की अनुमति देते हैं, जिससे परीक्षण नियतात्मक, तेज़ और बाहरी सेवाओं से स्वतंत्र हो जाते हैं।
मुख्य बिंदु
Test Doubles ऑटोमोटिव उद्योग (स्टंट डबल) से सॉफ़्टवेयर विकास में लाया गया शब्द है। जैसे एक स्टंट डबल खतरनाक दृश्य में अभिनेता की जगह लेता है, वैसे ही Test Double परीक्षण परिदृश्य में वास्तविक घटक को बदलता है। यह तब आवश्यक है जब वास्तविक निर्भरता उपलब्ध न हो, धीमी हो, गैर-नियतात्मक हो, या दुष्प्रभाव हों।
Test Double अवधारणा पाँच विशिष्ट प्रकारों को शामिल करती है, प्रत्येक अपना कार्य हल करता है। Meszaros की टाइपोलॉजी प्रामाणिक है और सभी आधुनिक परीक्षण मार्गदर्शिकाओं में उपयोग की जाती है। प्रकारों के बीच अंतर नियंत्रण और सत्यापन की डिग्री में है: सरल पैरामीटर भरने (Dummy) से लेकर पूर्ण कॉल अनुक्रम सत्यापन (Mock) तक।
Test Doubles का मुख्य उद्देश्य परीक्षण के तहत मॉड्यूल का अलगाव है। मोबाइल विकास में, वास्तविक निर्भरताओं में API सर्वर, डेटाबेस, फ़ाइल सिस्टम, डिवाइस सेंसर और सिस्टम सेवाएँ (LocationManager, Camera, Bluetooth) शामिल हैं। इन घटकों का सीधे उपयोग परीक्षणों को धीमा, नाज़ुक और पर्यावरण-निर्भर बनाता है। Google Testing Blog (2023) के अनुसार, अच्छी तरह से पृथक यूनिट टेस्ट मिलीसेकंड में चलते हैं, जबकि एकीकरण परीक्षण सेकंड और मिनटों में चलते हैं।
Gerard Meszaros का वर्गीकरण पाँच प्रकार के Test Doubles शामिल करता है, जो व्यवहार और उद्देश्य में भिन्न हैं। उनके बीच अंतर समझना सक्षम यूनिट परीक्षण की नींव है।
Dummy एक ऑब्जेक्ट है जो परीक्षण की जा रही विधि में पारित किया जाता है लेकिन कभी उपयोग नहीं किया जाता। Dummy केवल विधि हस्ताक्षर को संतुष्ट करने के लिए आवश्यक है। Kotlin में, यह अक्सर null, emptyList(), या स्टब्स वाला ऑब्जेक्ट होता है। Dummy में कोई तर्क नहीं होना चाहिए — यदि इसे कॉल किया जाता है, तो परीक्षण विफल होना चाहिए।
Fake एक इंटरफ़ेस का सरलीकृत लेकिन कार्यशील कार्यान्वयन है। Mock और Stub के विपरीत, Fake में वास्तविक व्यावसायिक तर्क होता है, लेकिन सरलीकृत रूप में। एक क्लासिक उदाहरण InMemoryUserRepository है, जो डेटाबेस के बजाय HashMap में डेटा संग्रहीत करता है। Fake का उपयोग तब किया जाता है जब आपको राज्य पर निर्भर तर्क का परीक्षण करने की आवश्यकता होती है, लेकिन वास्तविक बुनियादी ढाँचे के ओवरहेड के बिना।
| प्रकार | उद्देश्य | उदाहरण |
|---|---|---|
| Dummy | पैरामीटर भरना | null, खाली ऑब्जेक्ट |
| Fake | कार्यशील सरलीकृत कार्यान्वयन | InMemoryRepository |
| Stub | निश्चित मान लौटाना | when(api.getUser()).thenReturn(user) |
| Spy | सत्यापन के लिए कॉल रिकॉर्ड करना | verify(spy).save(user) |
| Mock | इंटरैक्शन सत्यापित करना | verify(mock).sendEmail(email) |
Stub विशिष्ट कॉल पर पूर्वनिर्धारित मान लौटाता है। Stub यह जाँच नहीं करता कि इसे कॉल किया गया था — यह केवल डेटा प्रदान करता है। Mockito में, Stub when(method).thenReturn(value) के माध्यम से बनाया जाता है। Stub परीक्षण के लिए आदर्श है जब आपको किसी निर्भरता को एक विशिष्ट मान लौटाने की आवश्यकता होती है, लेकिन कॉल का तथ्य स्वयं महत्वपूर्ण नहीं है।
Spy एक वास्तविक ऑब्जेक्ट के चारों ओर एक आवरण है जो बाद में सत्यापन के लिए सभी कॉल रिकॉर्ड करता है। Mock के विपरीत, Spy कॉल को वास्तविक ऑब्जेक्ट को सौंपता है लेकिन यह जाँचने की अनुमति देता है कि वे हुए। Mockito में, Spy spy(realObject) के माध्यम से बनाया जाता है। Spy आंशिक mocking के लिए उपयोगी है, जब आप वास्तविक ऑब्जेक्ट का उपयोग करना चाहते हैं लेकिन कुछ कॉल सत्यापित करना चाहते हैं।
Mock पूर्वनिर्धारित कॉल अपेक्षाओं वाला एक ऑब्जेक्ट है। Mock सत्यापित करता है कि विशिष्ट विधियों को विशिष्ट तर्कों और विशिष्ट क्रम में कॉल किया गया था। Stub के विपरीत, Mock डेटा वापसी के बजाय व्यवहार सत्यापन पर ध्यान केंद्रित करता है। Mock मोबाइल विकास में सबसे शक्तिशाली और सबसे अधिक उपयोग किया जाने वाला Test Double प्रकार है।
Mock और Stub के बीच अंतर अनुभवी डेवलपर्स के बीच भी अक्सर भ्रम पैदा करता है। मुख्य अंतर उद्देश्य में है: Stub स्थिति सत्यापन (state verification) की जाँच करता है, Mock व्यवहार सत्यापन (behavior verification) की जाँच करता है।
Stub प्रश्न का उत्तर देता है: “क्या कोड ने सही परिणाम लौटाया?”. Mock प्रश्न का उत्तर देता है: “क्या कोड ने सही तर्कों के साथ सही विधियों को कॉल किया?”. मोबाइल विकास में, Stub का उपयोग तब किया जाता है जब परिणाम मायने रखता है (जैसे, रिपॉजिटरी से डेटा), जबकि Mock का उपयोग तब किया जाता है जब दुष्प्रभाव मायने रखते हैं (जैसे, ईमेल भेजना, डेटाबेस में लिखना)।
// Stub: स्थिति सत्यापन
every { repository.getUsers() } returns listOf(user)
val result = useCase.getUsers()
assertEquals(1, result.size)
// Mock: व्यवहार सत्यापन
every { analytics.logEvent("purchase") } returns Unit
useCase.purchase(item)
verify { analytics.logEvent("purchase") }
MockK का उपयोग करके Kotlin में सभी पाँच प्रकार के Test Doubles के व्यावहारिक उदाहरण — Android परियोजनाओं के लिए सबसे लोकप्रिय mocking लाइब्रेरी।
class InMemoryUserRepository : UserRepository {
private val store = mutableMapOf<String, User>()
override fun save(user: User) {
store[user.email] = user
}
override fun findByEmail(email: String): User? {
return store[email]
}
}
class RegisterUseCaseTest {
private val api = mockk<AuthApi>()
private val repo = spyk(InMemoryUserRepository())
private val useCase = RegisterUseCase(api, repo)
fun `register user successfully`() = runTest {
// Stub: निश्चित API प्रतिक्रिया लौटाना
coEvery { api.register("test@test.com") } returns AuthResult.Success("token123")
val result = useCase.execute("test@test.com")
// Verify: सत्यापित करें कि उपयोगकर्ता सहेजा गया
verify { repo.save(any()) }
assertTrue(result.isSuccess())
}
}
data class Logger(val appContext: Context, val format: FormatType)
fun `test logger with dummy context`() {
// Dummy: Context का Logger के अंदर उपयोग नहीं किया गया
val dummyContext = mockk<Context>()
val logger = Logger(dummyContext, FormatType.JSON)
assertEquals(FormatType.JSON, logger.format)
}
Test Double प्रकार का चुनाव इस बात पर निर्भर करता है कि वास्तव में क्या परीक्षण किया जा रहा है: स्थिति, व्यवहार, या एकीकरण। Android और iOS मोबाइल विकास में, निम्नलिखित सिफारिशें स्थापित की गई हैं।
ViewModel का परीक्षण करते समय, दुष्प्रभाव उत्पन्न करने वाली निर्भरताओं (रिपॉजिटरी, एनालिटिक्स, नेविगेशन) के लिए Mock का उपयोग करें और डेटा लौटाने वाली निर्भरताओं (API क्लाइंट, ContentProvider) के लिए Stub का। यह सत्यापित करने की अनुमति देता है कि ViewModel सफलता और त्रुटि दोनों परिदृश्यों को सही ढंग से संभालता है।
Repository स्तर पर, Fake (इन-मेमोरी डेटाबेस कार्यान्वयन) और Stub (निश्चित API प्रतिक्रियाएँ) को प्राथमिकता दें। Fake SQLite सेट किए बिना कैशिंग तर्क और ऑफ़लाइन मोड का परीक्षण करने की अनुमति देता है। Stub विभिन्न HTTP स्थितियों का अनुकरण करता है: 200, 404, 500, timeout।
Test Doubles का गलत उपयोग सबसे आम कारणों में से एक है नाज़ुक परीक्षणों का जो हर रिफैक्टरिंग के साथ टूट जाते हैं।
सबसे आम गलती हर चीज़ को mock करना है। यदि परीक्षण में हर निर्भरता को Mock से बदल दिया जाता है, तो परीक्षण वास्तविक व्यवहार की जाँच करना बंद कर देता है। Mock का उपयोग केवल बाहरी निर्भरताओं के लिए होना चाहिए (नेटवर्क, डेटाबेस, फ़ाइल सिस्टम, सिस्टम सेवाएँ)। आंतरिक एप्लिकेशन घटकों (Value Object, data class, सरल उपयोगिताएँ) को प्रतिस्थापित नहीं किया जाना चाहिए।
दूसरी गलती बिना अपेक्षाएँ परिभाषित किए Mock बनाना है। यदि कोई विधि every / when के बिना कॉल की जाती है, तो Mock डिफ़ॉल्ट मान लौटाता है (null, 0, false)। यह गलत-सकारात्मक परीक्षणों का कारण बन सकता है, जहाँ Mock चुपचाप null लौटाता है और परीक्षण इसे सही व्यवहार के रूप में व्याख्यायित करता है।
तीसरी गलती हर Mock के हर कॉल को सत्यापित करना है। Verify का उपयोग केवल उन कॉल के लिए किया जाना चाहिए जो व्यावसायिक तर्क के दृष्टिकोण से महत्वपूर्ण हैं। अत्यधिक सत्यापन परीक्षणों को नाज़ुक बनाता है: प्रोडक्शन कोड में कॉल के क्रम को बदलना व्यवहार को बदले बिना परीक्षणों को तोड़ देता है।
अक्सर पूछे जाने वाले प्रश्न
Stub डेटा लौटाता है और स्थिति की जाँच करता है (क्या लौटाया गया), जबकि Mock व्यवहार की जाँच करता है (कौन सी विधियाँ कॉल की गईं)। Stub = “X लौटाओ”, Mock = “सत्यापित करो कि Y को तर्क Z के साथ कॉल किया गया”। वास्तविक परीक्षणों में, एक ऑब्जेक्ट अक्सर एक साथ Stub और Mock दोनों के रूप में कार्य करता है।
Fake Mock से बेहतर है जब स्थिति पर निर्भर तर्क का परीक्षण किया जाता है: कैशिंग, ऑफ़लाइन मोड, लेन-देन। Fake (इन-मेमोरी कार्यान्वयन) नाज़ुक verify कॉल के बिना इन परिदृश्यों का परीक्षण करने की अनुमति देता है। Mock डेटा भेजने की जाँच के लिए बेहतर उपयुक्त है: एनालिटिक्स, push, ईमेल।
Kotlin में Android परियोजनाओं के लिए, MockK अनुशंसित है। यह बिना अतिरिक्त कॉन्फ़िगरेशन के कोरूटीन, सस्पेंड फ़ंक्शन, सील्ड क्लास और एक्सटेंशन फ़ंक्शन का समर्थन करता है। Java परियोजनाओं के लिए, Mockito मानक बना हुआ है — व्यापक दस्तावेज़ीकरण वाली सबसे लोकप्रिय लाइब्रेरी।
Kotlin Flow का परीक्षण करने के लिए, MockK के साथ Turbine लाइब्रेरी का उपयोग करें। Turbine Flow उत्सर्जन की जाँच को सरल बनाती है: आप मानों के क्रम, स्ट्रीम पूर्णता और अपवादों को सत्यापित कर सकते हैं। Flow के लिए Stub flowOf(value) लौटाता है, Mock सत्यापित करता है कि Flow एकत्र किया गया था।
हाँ, लेकिन API प्रतिक्रियाओं के स्तर पर, UI घटकों के नहीं। MockWebServer (OkHttp) और WireMock लाइब्रेरीज़ UI परीक्षणों में HTTP प्रतिक्रियाओं को बदलने की अनुमति देती हैं। UI घटक स्वयं (Compose, SwiftUI Views) प्रतिस्थापित नहीं होने चाहिए — उनके व्यवहार का परीक्षण स्क्रीनशॉट परीक्षणों और Espresso के माध्यम से किया जाता है।
सारांश
हम एक मोबाइल एप्लिकेशन टर्नकी विकसित करेंगे
IT Sectr 2017 से स्टार्टअप और व्यवसायों के लिए iOS और Android एप्लिकेशन बनाता है। हम आपको सलाह देंगे और सर्वोत्तम समाधान प्रस्तावित करेंगे।
यह भी पढ़ें