MockK হল একটি Kotlin-first ফ্রেমওয়ার্ক যা mock-অবজেক্ট তৈরির জন্য, বিশেষভাবে Kotlin ইকোসিস্টেমের জন্য এর ভাষা বৈশিষ্ট্যগুলি বিবেচনা করে ডিজাইন করা হয়েছে: কোরুটিন, এক্সটেনশন ফাংশন, data class এবং sealed class। Mockito-এর বিপরীতে, যা Java থেকে Kotlin-এ পোর্ট করা হয়েছিল, MockK মূলত Kotlin সিনট্যাক্সের জন্য ডিজাইন করা হয়েছিল এবং ফাইনাল ক্লাসের সাথে কাজ করার জন্য অতিরিক্ত প্লাগইনের প্রয়োজন হয় না। 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-বান্ধব 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 অ্যাপ্লিকেশন তৈরি করে। আমরা আপনাকে পরামর্শ দেব এবং সেরা সমাধান প্রস্তাব করব।
আরও পড়ুন