MockK एक Kotlin-first फ्रेमवर्क है जो mock-ऑब्जेक्ट बनाने के लिए है, जिसे विशेष रूप से Kotlin इकोसिस्टम के लिए इसकी भाषा विशेषताओं को ध्यान में रखते हुए डिज़ाइन किया गया है: कोरूटीन, एक्सटेंशन फ़ंक्शन, data class और sealed class। Mockito के विपरीत, जिसे Java से Kotlin में पोर्ट किया गया था, MockK मूल रूप से Kotlin सिंटैक्स के लिए डिज़ाइन किया गया था और final क्लासेस के साथ काम करने के लिए अतिरिक्त प्लगइन्स की आवश्यकता नहीं है। MockK.io के अनुसार, लाइब्रेरी का उपयोग यूनिट टेस्टिंग वाले 40% से अधिक Kotlin प्रोजेक्ट्स में किया जाता है।
मुख्य बिंदु
MockK मॉक ऑब्जेक्ट बनाने के लिए एक लाइब्रेरी है, जो Kotlin में लिखी गई है और इसके सिंटैक्स के लिए अनुकूलित है। यह वही समस्याएँ हल करती है जो Mockito हल करता है — निर्भरताओं से परीक्षण किए जा रहे कोड को अलग करना — लेकिन यह Kotlin-विशिष्ट निर्माणों का उपयोग करके करता है: लैम्ब्डा, DSL, reified generics और suspend-फ़ंक्शन।
पोर्ट किए गए समाधानों पर MockK का मुख्य लाभ देशी Kotlin समर्थन है। Mockito में, फ़ाइनल क्लास को मॉक करने के लिए opt-in (mockito-inline) की आवश्यकता होती है, और स्टैटिक मेथड के लिए mockStatic की। MockK डिफ़ॉल्ट रूप से इसका समर्थन करता है, क्योंकि Kotlin क्लासेस डिफ़ॉल्ट रूप से फ़ाइनल होती हैं, और इस सीमा को बायपास करना लाइब्रेरी की आर्किटेक्चर में बनाया गया है।
संस्करण 1.13.12 (2024) एक स्थिर रिलीज़ है जो Kotlin 2.0, K2 कंपाइलर और मल्टीप्लेटफ़ॉर्म प्रोजेक्ट्स (KMP) का समर्थन करता है। MockK Kotlin/Native और Kotlin/JS के साथ भी काम करता है, जो इसे KMP प्रोजेक्ट्स के लिए एकमात्र विकल्प बनाता है जहाँ न तो Mockito और न ही EasyMock लागू होते हैं।
MockK को Kotlin की विशिष्टताओं को ध्यान में रखकर डिज़ाइन किया गया है और प्रदर्शन का त्याग किए बिना एक संक्षिप्त और type-safe API प्रदान करने के लिए भाषा सुविधाओं — reified generics, लैम्ब्डा के साथ DSL, इनलाइन फ़ंक्शन — का उपयोग करता है।
MockK का तंत्र ByteBuddy लाइब्रेरी के माध्यम से बाइटकोड इंस्ट्रूमेंटेशन पर आधारित है (Mockito की तरह), लेकिन इसे Kotlin-friendly DSL में लपेटता है। when().thenReturn() चेन के बजाय, MockK लैम्ब्डा ब्लॉक every { } और coEvery { } का उपयोग करता है जो भाषा के प्राकृतिक विस्तार की तरह दिखते हैं। हुड के नीचे, MockK लैम्ब्डा के अंदर कॉल को इंटरसेप्ट करता है, रिफ्लेक्शन के माध्यम से विधि और तर्कों का विश्लेषण करता है और उन्हें रिकॉर्ड किए गए स्टबिंग नियमों से मिलाता है।
ब्लॉक every { mock.method() } returns value को “हर बार जब विधि कॉल की जाती है, मान लौटाएँ” के रूप में पढ़ा जाता है। यह घोषणात्मक सिंटैक्स Kotlin शैली के करीब है और when() में तर्क क्रम के साथ भ्रम को समाप्त करता है। Kotlin के reified generics के लिए धन्यवाद, मॉक प्रकार बिना स्पष्ट रूप से क्लास निर्दिष्ट किए स्वचालित रूप से अनुमानित होता है।
val repository = mockk<UserRepository>()
// Stubbing: findById(1) की प्रत्येक कॉल उपयोगकर्ता लौटाती है
every { repository.findById(1) } returns User("Alice")
// कॉल और सत्यापन
val result = repository.findById(1)
assertEquals("Alice", result.name)
Mockito के विपरीत, जहाँ प्रत्येक विधि को स्पष्ट रूप से कॉन्फ़िगर किया जाना चाहिए, MockK relaxed mock का समर्थन करता है — एक मॉक जो किसी भी विधि के लिए “उचित” डिफ़ॉल्ट मान लौटाता है: List के लिए खाली सूची, Int के लिए 0, String के लिए खाली स्ट्रिंग। यह सेटअप कोड की मात्रा को नाटकीय रूप से कम करता है।
// Relaxed mock — सभी विधियाँ डिफ़ॉल्ट मान लौटाती हैं
val api = mockk<ApiService>(relaxed = true)
// स्टबिंग की आवश्यकता नहीं — खाली सूची लौटाता है
println(api.getUsers()) // []
MockK मॉक ऑब्जेक्ट बनाने के कई तरीके प्रदान करता है: सख्त मॉक के लिए mockk<T>() (प्रत्येक विधि को स्पष्ट रूप से कॉन्फ़िगर किया जाना चाहिए), रिलैक्स्ड मॉक के लिए mockk<T>(relaxed = true) और वास्तविक ऑब्जेक्ट पर स्पाई बनाने के लिए spyk(obj)।
| फ़ंक्शन | प्रकार | स्टबिंग के बिना व्यवहार |
|---|---|---|
| mockk() | सख्त मॉक | गैर-स्टब की गई विधि कॉल करने पर अपवाद फेंकता है |
| mockk(relaxed = true) | रिलैक्स्ड मॉक | डिफ़ॉल्ट मान लौटाता है |
| spyk() | स्पाई | यदि स्टब कॉन्फ़िगर नहीं है तो वास्तविक विधि कॉल करता है |
| slot() | Argument Captor | सत्यापन के लिए तर्क कैप्चर करता है |
सख्त और रिलैक्स्ड मॉक के बीच चुनाव संदर्भ पर निर्भर करता है। एक सख्त मॉक गारंटी देता है कि परीक्षण उन विधियों का उपयोग नहीं करता है जिनका व्यवहार परिभाषित नहीं है — यह विश्वसनीयता बढ़ाता है। रिलैक्स्ड मॉक त्वरित परीक्षण प्रोटोटाइपिंग के लिए सुविधाजनक है जहाँ सभी निर्भरताएँ मायने नहीं रखती हैं। व्यवहार में, सख्त मॉक से शुरू करने और केवल तभी रिलैक्स्ड पर स्विच करने की सिफारिश की जाती है जब स्टबिंग परीक्षण से अधिक लाइनें लेती है।
Every ब्लॉक MockK में केंद्रीय स्टबिंग निर्माण है। लैम्ब्डा के अंदर, विशिष्ट तर्कों के साथ एक विधि कॉल का वर्णन किया जाता है, और फिर returns के माध्यम से एक मान लौटाया जाता है, throws के माध्यम से एक अपवाद फेंका जाता है, या answers के माध्यम से प्रतिक्रिया की गणना की जाती है।
MockK परीक्षण के लिए आवश्यक सभी परिदृश्यों का समर्थन करता है: मान लौटाना, अपवाद फेंकना, तर्कों के आधार पर प्रतिक्रिया की गणना करना, और क्रम में कई उत्तर (कॉल अनुक्रम)।
// मान लौटाना
every { repo.findById(1) } returns User("Alice")
// अपवाद फेंकना
every { repo.findById(999) } throws NotFoundException()
// गतिशील उत्तर
every { repo.save(any()) } answers {
val user = firstArg<User>()
user.copy(id = 42)
}
// उत्तरों का क्रम
every { repo.findAll() } returnsMany listOf(
listOf(User("Alice")),
listOf(User("Bob")),
emptyList()
)
Verify MockK में उद्देश्य में Mockito.verify() के समान है, लेकिन Kotlin DSL का उपयोग करता है: verify { mock.method() }। Suspend-फ़ंक्शन के लिए coVerify { mock.suspendMethod() } का उपयोग किया जाता है, जो कोरूटीन के साथ सही ढंग से काम करता है और किसी विशेष रनर की आवश्यकता नहीं है।
MockK उन्हीं मॉडिफ़ायर का समर्थन करता है जो Mockito करता है: exactly(1), atLeast(2), atMost(5), wasNot(Called)। सिंटैक्स न्यूनतम है — मॉडिफ़ायर को verify { } में पहले तर्क के रूप में पास किया जाता है।
// सत्यापन: विधि ठीक 1 बार कॉल हुई
verify(exactly = 1) { repo.save(any()) }
// कॉल ऑर्डर सत्यापित करें
verifySequence {
repo.save(any())
repo.flush()
}
// suspend-फ़ंक्शन के लिए coVerify
coVerify { api.fetchUsers() }
तर्क सत्यापन के लिए slot() का उपयोग किया जाता है — जो ArgumentCaptor का एनालॉग है। Slot को कॉल से पहले घोषित किया जाता है, every या verify में पास किया जाता है, और परीक्षण निष्पादन के बाद कैप्चर किए गए मान को रखता है।
val userSlot = slot<User>()
verify { repo.save(capture(userSlot)) }
assertEquals("Alice", userSlot.captured.name)
MockK JUnit 5 में आरंभीकरण के माध्यम से मॉक बनाने के लिए @MockK और @RelaxedMockK एनोटेशन प्रदान करता है। MockKExtension प्रत्येक परीक्षण से पहले स्वचालित रूप से मॉक बनाता है और बाद में साफ करता है — MockitoExtension के समान, लेकिन रिलैक्स्ड मोड समर्थन के साथ।
@InjectMockKs एनोटेशन (या वैकल्पिक @MockK स्पष्ट ऑब्जेक्ट निर्माण के साथ) परीक्षण किए जा रहे इंस्टेंस में मॉक इंजेक्ट करता है। यह बॉयलरप्लेट को कम करता है और परीक्षण कोड को साफ बनाता है।
@ExtendWith(MockKExtension::class)
class UserServiceTest {
@MockK
lateinit var repository: UserRepository
@InjectMockKs
lateinit var service: UserService
@Test
fun `getUser returns user from repository`() {
every { repository.findById(1) } returns User("Alice")
assertEquals("Alice", service.getUser(1)?.name)
}
}
चुनाव MockK और Mockito के बीच टीम की संरचना और प्रोजेक्ट के प्रकार पर निर्भर करता है। Mockito का पारिस्थितिकी तंत्र बड़ा है, अधिक उदाहरण और एकीकरण हैं, लेकिन MockK क्लीनर Kotlin सिंटैक्स और भाषा सुविधाओं के लिए देशी समर्थन प्रदान करता है। नए Kotlin प्रोजेक्ट्स के लिए, MockK को अधिक मुहावरेदार समाधान के रूप में अनुशंसित किया जाता है।
| मानदंड | MockK | Mockito |
|---|---|---|
| सिंटैक्स | Kotlin DSL (every, verify) | Java-शैली (when, thenReturn) |
| कोरूटीन | coEvery, coVerify (देशी) | अतिरिक्त लाइब्रेरी आवश्यक |
| Final क्लास | डिफ़ॉल्ट रूप से समर्थित | mockito-inline आवश्यक |
| KMP | समर्थित | समर्थित नहीं |
| Relaxed mock | अंतर्निर्मित | कोई विकल्प नहीं |
| लोकप्रियता | Kotlin समुदाय में बढ़ रही है | Java और हाइब्रिड प्रोजेक्ट्स में प्रमुख |
शुद्ध Kotlin प्रोजेक्ट्स (Java क्लासेस के बिना) के लिए MockK बेहतर है: कम बॉयलरप्लेट, देशी कोरूटीन समर्थन, फ़ाइनल क्लासेस के साथ कोई आश्चर्य नहीं। हाइब्रिड प्रोजेक्ट्स या Java पृष्ठभूमि वाली टीमों के लिए, Mockito एक काम करने वाला विकल्प बना हुआ है — दोनों लाइब्रेरी का उपयोग विभिन्न मॉड्यूल के माध्यम से एक ही प्रोजेक्ट में किया जा सकता है। Mockito से MockK में माइग्रेट करते समय, @Mock एनोटेशन को @MockK से बदलना और when().thenReturn() ब्लॉक को every { } प्रारूप में फिर से लिखना पर्याप्त है।
अक्सर पूछे जाने वाले प्रश्न
Relaxed mock सभी गैर-स्टब की गई विधियों के लिए डिफ़ॉल्ट मान लौटाता है (खाली सूची, 0, null) बिना अपवाद फेंके। सामान्य (सख्त) मॉक को प्रत्येक विधि के स्पष्ट स्टबिंग की आवश्यकता होती है — अन्यथा परीक्षण विफल हो जाता है। Relaxed mock त्वरित परीक्षणों के लिए सुविधाजनक है, सख्त विश्वसनीय परीक्षणों के लिए।
MockK mockkStatic() के माध्यम से एक्सटेंशन फ़ंक्शन की मॉकिंग का समर्थन करता है। यह संभव है क्योंकि Kotlin में एक्सटेंशन फ़ंक्शन पहले पैरामीटर के रूप में रिसीवर के साथ स्टैटिक विधियाँ हैं। प्रत्येक एक्सटेंशन फ़ंक्शन के लिए, आपको वह क्लास निर्दिष्ट करना होगा जिसमें इसे घोषित किया गया है।
हाँ, MockK सामान्य कोड के लिए Kotlin Multiplatform (KMP) का समर्थन करता है। JVM, Native और JS प्लेटफ़ॉर्म पर, आप सामान्य API: mockk(), every, verify का उपयोग कर सकते हैं। यह MockK को KMP प्रोजेक्ट्स के लिए एकमात्र विकल्प बनाता है जहाँ Mockito काम नहीं करता है।
verifySequence { } का उपयोग करें — एक ब्लॉक जहाँ कॉल सख्ती से अपेक्षित क्रम में निर्दिष्ट की जाती हैं। यदि वास्तविक क्रम भिन्न है, तो verifySequence पहली बेमेल कॉल का संकेत देते हुए अपवाद फेंकेगा।
हाँ, तकनीकी रूप से यह संभव है, लेकिन अनुशंसित नहीं है। बाइटकोड इंस्ट्रूमेंटेशन स्तर (ByteBuddy बनाम mockito-inline) पर विरोध हो सकता है। यदि प्रोजेक्ट पहले से Mockito का उपयोग करता है, तो MockK में माइग्रेशन मॉड्यूल अलगाव के माध्यम से क्रमिक हो सकता है।
निष्कर्ष
हम एक मोबाइल एप्लिकेशन टर्नकी विकसित करेंगे
IT Sectr 2017 से स्टार्टअप और व्यवसायों के लिए iOS और Android एप्लिकेशन बनाता है। हम आपको सलाह देंगे और सर्वोत्तम समाधान प्रस्तावित करेंगे।
यह भी पढ़ें