Mockito একটি ওপেন-সোর্স ফ্রেমওয়ার্ক যা Java এবং Kotlin ইউনিট টেস্টে mock-অবজেক্ট তৈরি করার জন্য, যা টেস্ট করা কোডকে বাহ্যিক নির্ভরশীলতা থেকে আলাদা করতে দেয়। এর সাহায্যে, ডেভেলপার প্রকৃত রিপোজিটরি, API ক্লায়েন্ট এবং ডেটাবেসকে নিয়ন্ত্রিত স্টাব দিয়ে প্রতিস্থাপন করে যার পূর্বনির্ধারিত আচরণ থাকে। Mockito.org-এর তথ্য অনুযায়ী, লাইব্রেরিটি ইউনিট টেস্টিং ব্যবহার করে এমন 60%-এর বেশি Java প্রকল্পে ব্যবহৃত হয়।
মূল পয়েন্ট
Mockito Java, Kotlin এবং অন্যান্য JVM ভাষায় ইউনিট টেস্টের জন্য mock-অবজেক্ট (স্টাব) তৈরি করার একটি ওপেন-সোর্স লাইব্রেরি। JUnit-এর বিপরীতে, যা টেস্ট এক্সিকিউশনের জন্য দায়ী, Mockito আইসোলেশন সমস্যার সমাধান করে — এটি টেস্ট করা ক্লাসের প্রকৃত নির্ভরশীলতাকে পূর্বাভাসযোগ্য অবজেক্ট দিয়ে প্রতিস্থাপন করে।
mock ছাড়া, একটি মেথড টেস্ট করা যা ডেটাবেস বা বাহ্যিক API-তে অ্যাক্সেস করে, প্রকৃত পরিবেশ সেটআপের প্রয়োজন — ডেটাবেস ডিপ্লয় করা, সার্ভার চালু করা। Mockito এই নির্ভরশীলতাগুলোকে নির্দিষ্ট আচরণ সহ অবজেক্ট দিয়ে প্রতিস্থাপন করে: repository.findById(1) মেথড সবসময় ডেটাবেসে অ্যাক্সেস না করেই একটি নির্দিষ্ট User অবজেক্ট রিটার্ন করে।
Mockito-র আর্কিটেকচার Proxy প্যাটার্নের (ইন্টারফেস এবং ক্লাসের জন্য) উপর ভিত্তি করে তৈরি। লাইব্রেরি নির্দিষ্ট টাইপের জন্য একটি সাবক্লাস বা প্রক্সি জেনারেট করে এবং সব মেথড কল ইন্টারসেপ্ট করে, ডিফল্ট ভ্যালু বা when().thenReturn()-এর মাধ্যমে সেট করা ভ্যালু রিটার্ন করে।
Mockito-র কাজের নীতি তিনটি মৌলিক অপারেশনের উপর নির্মিত: mock তৈরি করা, আচরণ কনফিগার করা (stubbing) এবং কল যাচাই করা (verification)। প্রতিটি অপারেশন org.mockito.Mockito ক্লাস থেকে স্ট্যাটিক মেথড ব্যবহার করে — Maven Central-এর পরিসংখ্যান অনুযায়ী Java ইকোসিস্টেমে এটি সবচেয়ে বেশি ডাউনলোড করা ক্লাস। সব mock মেথড কল মেমোরিতে রেকর্ড করা হয়, যা পরে verify-এর মাধ্যমে যাচাইয়ের অনুমতি দেয়।
Mockito-র সাথে একটি সাধারণ টেস্ট তিনটি ফেজ নিয়ে গঠিত: Arrange — when().thenReturn()-এর মাধ্যমে mock তৈরি এবং স্টাব কনফিগার করা, Act — টেস্ট করা মেথড কল করা, Assert — assertEquals এবং verify(mock)-এর মাধ্যমে ফলাফল যাচাই করা। এই পদ্ধতিকে AAA (Arrange-Act-Assert) বলা হয়।
একটি সহজ টেস্ট দেখি যেখানে Mockito ইউজার রিপোজিটরি প্রতিস্থাপন করে। when().thenReturn() মেথড mock-কে এমনভাবে কনফিগার করে যে findById কল একটি পূর্ব-প্রস্তুত User অবজেক্ট রিটার্ন করে।
// রিপোজিটরি mock তৈরি করা
UserRepository mockRepo = mock(UserRepository.class);
// আচরণ কনফিগার করা: findById(1) একজন ব্যবহারকারী রিটার্ন করে
when(mockRepo.findById(1)).thenReturn(new User("Alice"));
// যাচাই করা যে মেথডটি সত্যিই কল করা হয়েছিল
User result = mockRepo.findById(1);
assertEquals("Alice", result.getName());
verify(mockRepo).findById(1);
Mockito mock তৈরি করার দুটি উপায় প্রদান করে: স্ট্যাটিক মেথড mock(Class) এবং @Mock অ্যানোটেশন MockitoAnnotations.openMocks()-এর মাধ্যমে ইনিশিয়ালাইজেশন সহ। প্রথম উপায়টি এক-দুটি mock-এর জন্য কমপ্যাক্ট, দ্বিতীয়টি সুবিধাজনক যখন অনেক নির্ভরশীলতা থাকে — অ্যানোটেশন boilerplate কোড কমায়।
mock() মেথড একটি ক্লাস নেয় এবং একটি স্টাব অবজেক্ট রিটার্ন করে যা when().thenReturn()-এর মাধ্যমে কনফিগার করা যায়। সব অকনফিগার মেথড ডিফল্ট ভ্যালু রিটার্ন করে: সংখ্যার জন্য 0, boolean-এর জন্য false, অবজেক্টের জন্য null।
ApiClient apiClient = mock(ApiClient.class);
Database database = mock(Database.class);
@Mock অ্যানোটেশন @ExtendWith(MockitoExtension.class)-এর সাথে মিলে টেস্ট ক্লাসের সব ফিল্ডের জন্য স্বয়ংক্রিয়ভাবে mock তৈরি করে। MockitoExtension প্রতিটি টেস্টের আগে ইনিশিয়ালাইজেশনের জন্য দায়ী।
@ExtendWith(MockitoExtension.class)
class UserServiceTest {
@Mock
private UserRepository userRepository;
@InjectMocks
private UserService userService;
@Test
void getUserShouldReturnUserFromRepo() {
when(userRepository.findById(1)).thenReturn(new User("Alice"));
User result = userService.getUser(1);
assertEquals("Alice", result.getName());
}
}
Stubbing হল নির্দিষ্ট আর্গুমেন্ট সহ কল করার সময় mock মেথড কী রিটার্ন করবে তা নির্ধারণের প্রক্রিয়া। মৌলিক সিনট্যাক্স: when(mock.method(args)).thenReturn(value)। বিভিন্ন পরিস্থিতির জন্য, Mockito বেশ কয়েকটি then-মেথড ভেরিয়েন্ট অফার করে।
| মেথড | উদ্দেশ্য |
|---|---|
| thenReturn(value) | সবসময় নির্দিষ্ট ভ্যালু রিটার্ন করে |
| thenThrow(exception) | কল করার সময় এক্সেপশন থ্রো করে |
| thenAnswer(answer) | ডায়নামিকভাবে রিটার্ন ভ্যালু গণনা করে |
| thenCallRealMethod() | প্রকৃত মেথড কল করে (আংশিক mock) |
যখন রিটার্ন ভ্যালু কল আর্গুমেন্টের উপর নির্ভর করে, তখন lambda-সহ thenAnswer ব্যবহার করা হয়। এটি প্রকৃত ডেটার সাথে কাজ অনুকরণের জন্য উপযোগী — উদাহরণস্বরূপ, পাস করা অবজেক্টের উপর ভিত্তি করে ID জেনারেট করা।
when(repository.save(any())).thenAnswer(invocation -> {
User user = invocation.getArgument(0);
user.setId(42);
return user;
});
Verify Mockito-র একটি অনন্য বৈশিষ্ট্য যা পুরনো mock-অবজেক্ট লাইব্রেরি (EasyMock, jMock) প্রদান করে না।
Verify টেস্টকে আরও নির্ভরযোগ্য করে তোলে কারণ এটি শুধু রিটার্ন ভ্যালু নয়, বরং সাইড ইফেক্টও পরীক্ষা করে — যে মেথডগুলো ফলাফল রিটার্ন করে না (void মেথড) সেগুলোর কল। verify(mock).methodName(args) মেথড যাচাই করে যে নির্দিষ্ট mock মেথডটি নির্দিষ্ট আর্গুমেন্ট সহ কল করা হয়েছিল কিনা। এটি শুধু ফলাফল নয়, বরং প্রক্রিয়াও পরীক্ষা করার অনুমতি দেয় — নির্ভরশীলতায় অ্যাক্সেসের ঘটনা।
ডিফল্টভাবে, verify যাচাই করে যে মেথডটি ঠিক একবার কল করা হয়েছিল। যদি ভিন্ন সংখ্যার প্রয়োজন হয়, তাহলে times(n), atLeast(n), never() এবং Mockito ক্লাসের অন্যান্য মডিফায়ার ব্যবহার করা হয়।
// কলের সংখ্যা যাচাই করা
verify(repository, times(3)).save(any());
verify(repository, never()).delete(any());
verify(repository, atLeastOnce()).findById(1);
// কলের ক্রম যাচাই করা
InOrder inOrder = inOrder(repository);
inOrder.verify(repository).save(any());
inOrder.verify(repository).flush();
যখন আপনাকে যাচাই করতে হবে যে মেথডটি ঠিক কোন অবজেক্টের সাথে কল করা হয়েছিল, তখন ArgumentCaptor ব্যবহার করা হয়। এটি কলের সময় আর্গুমেন্ট ভ্যালু ক্যাপচার করে এবং এর ফিল্ডগুলো পৃথকভাবে পরীক্ষা করার অনুমতি দেয়। ArgumentCaptor বিশেষভাবে উপযোগী যখন টেস্ট করা কোড অভ্যন্তরীণভাবে একটি অবজেক্ট তৈরি করে এবং এটি একটি নির্ভরশীলতায় পাস করে — আপনি অন্যথায় সেই অবজেক্টটি পরীক্ষা করতে পারবেন না।
ArgumentCaptor<User> captor = ArgumentCaptor.forClass(User.class);
verify(repository).save(captor.capture());
assertEquals("Alice", captor.getValue().getName());
@Mock এবং @InjectMocks হল দুটি মূল Mockito অ্যানোটেশন যা boilerplate কোড উল্লেখযোগ্যভাবে কমায়। @Mock একটি ফিল্ডের জন্য mock তৈরি করে, এবং @InjectMocks টেস্ট ক্লাস থেকে সব mock টেস্ট করা অবজেক্টে কনস্ট্রাক্টর, সেটার বা ফিল্ডের মাধ্যমে ইনজেক্ট করে।
@InjectMocks মেকানিজম নিম্নলিখিত ক্রমে নির্ভরশীলতা ইনজেক্ট করার চেষ্টা করে: সবচেয়ে বেশি আর্গুমেন্ট সহ কনস্ট্রাক্টর, টাইপ অনুসারে সেটার, প্রাইভেট ফিল্ড। যদি এই পদ্ধতিগুলোর কোনোটিই কাজ না করে, তাহলে অবজেক্টটি null নির্ভরশীলতা সহ থাকে এবং টেস্টটি NullPointerException-এর সাথে ব্যর্থ হবে।
এটা বোঝা গুরুত্বপূর্ণ: @InjectMocks ফিল্ড টাইপ বিশ্লেষণ করে না — এটি টাইপ অনুসারে সামঞ্জস্যপূর্ণ যেকোনো mock প্রতিস্থাপন করে। যদি একটি ক্লাসে একই টাইপের দুটি ফিল্ড থাকে, তাহলে Mockito ভুল mock ইনজেক্ট করতে পারে। এই ধরনের ক্ষেত্রে, mock প্যারামিটার সহ স্পষ্ট কনস্ট্রাক্টর ব্যবহার করার পরামর্শ দেওয়া হয়।
Android ডেভেলপমেন্টে, Mockito JUnit-এর সাথে ViewModel, Repository এবং UseCase টেস্ট করার জন্য ব্যবহৃত হয়। যেহেতু এই ক্লাসগুলো Android কনটেক্সট ছাড়া JVM-এ চলে, Mockito তাদের নির্ভরশীলতা — Room DAO, Retrofit API, SharedPreferences — পূর্বাভাসযোগ্য আচরণ সহ স্টাব দিয়ে প্রতিস্থাপন করে।
Android প্রকল্পে Mockito যোগ করার জন্য, শুধু mockito-core বা mockito-inline নির্ভরশীলতা যোগ করুন (পরবর্তীটি ফাইনাল ক্লাস এবং স্ট্যাটিক মেথডের mocking সমর্থন করে)। সংস্করণ 5.12.0 (2024) Java 21 সমর্থন এবং উন্নত JUnit 5 ইন্টিগ্রেশন অন্তর্ভুক্ত করে।
// build.gradle.kts (module)
dependencies {
testImplementation("org.mockito:mockito-core:5.12.0")
testImplementation("org.mockito:mockito-junit-jupiter:5.12.0")
}
পূর্বে, স্ট্যাটিক মেথড এবং কনস্ট্রাক্টরের mocking-এর জন্য PowerMock প্রয়োজন ছিল — একটি এক্সটেনশন যা বাইটকোড ইন্সট্রুমেন্টেশনের মাধ্যমে কাজ করত। Mockito 5.x থেকে mockito-inline-এর সাথে, এই ক্ষমতা সরাসরি অন্তর্নির্মিত: mockStatic(ClassName.class) অতিরিক্ত লাইব্রেরি ছাড়াই স্ট্যাটিক মেথডের mocking-এর অনুমতি দেয়।
একটি সাধারণ পরিস্থিতি: একটি ViewModel রিপোজিটরি মেথড কল করে এবং ফলাফলকে UI স্টেটে রূপান্তর করে। Mockito রিপোজিটরি প্রতিস্থাপন করে, এবং টেস্ট যাচাই করে যে ViewModel সফল প্রতিক্রিয়া এবং ত্রুটি উভয়ই সঠিকভাবে হ্যান্ডেল করে। Clean Architecture ব্যবহার করার সময়, প্রতিটি লেয়ারের জন্য mock তৈরি করা হয়: DataSource, Repository এবং UseCase — এটি প্রতিটি লেয়ারকে আলাদাভাবে টেস্ট করার অনুমতি দেয়।
প্রায়শই জিজ্ঞাসিত প্রশ্ন
Mockito Java এবং Kotlin-এর জন্য একটি লাইব্রেরি যা প্রক্সি এবং রিফ্লেকশন ব্যবহার করে। MockK একটি Kotlin-first লাইব্রেরি যা অতিরিক্ত কনফিগারেশন ছাড়াই করুটিন, এক্সটেনশন ফাংশন এবং ফাইনাল ক্লাস সমর্থন করে।
Mockito 2.1 থেকে শুরু করে, ফাইনাল ক্লাসের mocking opt-in-এর মাধ্যমে সমর্থিত। সংস্করণ 5.x (mockito-inline)-এ, এটি ডিফল্টভাবে সক্রিয়। শুধু mockito-inline নির্ভরশীলতা যোগ করুন এবং স্ট্যান্ডার্ড mock() মেথড ব্যবহার করুন।
Spy একটি আংশিক mock যা ডিফল্টভাবে প্রকৃত মেথড কল করে কিন্তু when().thenReturn()-এর মাধ্যমে সেগুলোর কিছু ওভাররাইড করার অনুমতি দেয়। Spy লিগ্যাসি কোড টেস্ট করার জন্য উপযোগী যখন পুরো ক্লাস পুনরায় লেখা সম্ভব নয়।
thenReturn সবসময় আর্গুমেন্ট নির্বিশেষে একই ভ্যালু রিটার্ন করে। thenAnswer ইনভোকেশন — কল আর্গুমেন্ট, mock নিজে এবং স্টেট — এর উপর ভিত্তি করে রিটার্ন ভ্যালু গণনা করে। ডায়নামিক রেসপন্সের জন্য, সবসময় thenAnswer ব্যবহার করুন।
Verify শুধু ফলাফল নয়, বরং প্রক্রিয়াও পরীক্ষা করে — নির্ভরশীলতায় অ্যাক্সেসের ঘটনা। এটি সেই সার্ভিসগুলোর জন্য গুরুত্বপূর্ণ যা ডেটা সংরক্ষণ বা নোটিফিকেশন পাঠাতে হবে। Verify ছাড়া, টেস্ট সনাক্ত করতে পারবে না যে একটি মেথড save() বা send() কল করেনি।
সারসংক্ষেপ
আমরা একটি মোবাইল অ্যাপ্লিকেশন টার্নকি তৈরি করব
IT Sectr 2017 সাল থেকে স্টার্টআপ এবং ব্যবসার জন্য iOS এবং Android অ্যাপ্লিকেশন তৈরি করে। আমরা আপনাকে পরামর্শ দেব এবং সেরা সমাধান প্রস্তাব করব।
আরও পড়ুন