Stub (স্টাব, টেস্ট ডবল) — একটি টেস্ট অবজেক্ট যা বাস্তব বাস্তবায়নের পরিবর্তে মেথড কলে পূর্বনির্ধারিত প্রতিক্রিয়া ফেরত দেয়। মোবাইল ডেভেলপমেন্টে, স্টাব পরীক্ষিত মডিউলকে নেটওয়ার্ক অনুরোধ, ডাটাবেস এবং ফাইল সিস্টেম থেকে পৃথক করে, যা পরিবেশ সেটআপ ছাড়াই যুক্তি যাচাই করতে দেয়। mock হতে ভিন্ন, stub আচরণ যাচাই করে না — এটি কেবল ডাটা প্রদান করে। আরও বিস্তারিত জানতে, দেখুন টেস্ট ডবলস নিয়ে Martin Fowler এর নিবন্ধ।
মূখ্য বিষয়
Stub একটি টেস্ট ডবল অবজেক্ট যা একটি পরীক্ষায় একটি বাস্তব নির্ভরতা প্রতিস্থাপন করে এবং নির্দিষ্ট কলের জন্য পূর্বনির্ধারিত মান ফেরত দেয়। শব্দটি Gerard Meszaros (2007) এর বর্গীকরণে বই «xUnit Test Patterns» এ প্রবর্তিত হয়েছিল। Stub test doubles বিভাগের অন্তর্ভুক্ত — অবজেক্ট যা পরীক্ষার সময় বাস্তব উপাদান প্রতিস্থাপন করে। স্টাবের প্রধান উদ্দেশ্য হল পরীক্ষিত ইউনিটকে পূর্বানুমানযোগ্য ডাটা প্রদান করা, বাহ্য সিস্টেম থেকে অনিশ্চিততা দূর করা।
কাজের নীতি — পরীক্ষা চালানোর আগে স্টাব কনফিগার করে: «যখন getUsers() মেথড কল করা হবে, তখন ব্যবহারকারীদের এই তালিকা ফেরত দাউ»। Stub এ কোনো ব্যবসায়িক যুক্তি নেই, এটি কল ক্রম যাচাই করে না এবং কল ইতিহাস রেকর্ড করে না। এটি কেবল বাস্তব উপাদানের জায়গায় দাঁড়িয়ে থাকে এবং যা বলা হয়েছে তা ফেরত দেয়। Android টেস্টিং প্রসঙ্গে, এটি বোঝায়: OkHttp ক্লায়েন্ট সরভারে বাস্তব অনুরোধ করে না, বরং স্টাব হিসেবে কনফিগার করা MockWebServer থেকে প্রতিক্রিয়া পেয়।
কথায় ব্যবহার করবেন — স্টাব UI স্তর (ViewModel, Presenter) এবং ব্যবসায়িক যুক্তি (UseCase, Interactor) পরীক্ষার জন্য আদর্শ, যেখানে আপনাকে নির্দিষ্ট ডাটায় প্রতিক্রিয়া যাচাই করতে হবে: খালি তালিকা, সরভার 500 ত্রুটি ফেরত দিয়েছে, টোকন মেয়ে গিয়েছে। যে কোনো ক্ষেত্রে যেখানে পরীক্ষার একটি নির্দিষ্ট ইনপুট অবস্থা প্রয়োজন হলে, তাটি stub এর কাজ। প্রতিটি পরীক্ষা পরিদৃশ্যের নিজস্ব স্টাব কনফিগরেশন তৈরি করা হয়, যা পরীক্ষাগুলিকে পড়তে সহজ এবং পূর্বানুমানযোগ্য করে।
Gerard Meszaros (2007) বই «xUnit Test Patterns» এ পাঁচটি test doubles চিহ্নিত করেছেন: dummy, stub, spy, mock, fake। প্রতিটি ধরন নিজস্ব সমস্যা সমাধান করে। Dummy — পাস করা হয় কিন্তু ব্যবহৃত হয় না। Stub — ডাটা ফেরত দেয়। Spy — কল রেকর্ড করে। Mock — আচরণ যাচাই করে। Fake — সরল যুক্তি ধারণ করে। এই বর্গীকরণ বোঝা ডেভেলপারকে প্রতিটি পরীক্ষা পরিদৃশ্যের জন্য সঠিক টুল বাচতে সাহায্য করে।
নেটওয়ার্ক অনুরোধ — স্টাব ব্যবহারের সবচেয়ে সাধারণ পরিদৃশ্য। অ্যাপ্লিকেশন API তে HTTP কল করে, এবং পরীক্ষায় বিভিন্ন প্রতিক্রিয়ায় প্রতিক্রিয়া যাচাই করতে হবে: সফল JSON, 401 ত্রুটি (অনাধিকৃত), টাইমআউট, খালি অ্যারে। Android এ MockWebServer (OkHttp) এবং URLProtocol (iOS) স্টাব হিসেবে কাজ করে, বাস্তব সরভার সংযোগ ছাড়াই পূর্বনির্ধারিত HTTP প্রতিক্রিয়া ফেরত দেয়। এটি পরীক্ষাগুলিকে সেকেন্ড থেকে মিলিসেকেন্ডে তবরানো করে।
ডাটাবেস — Room (Android) এবং CoreData (iOS) এ ইন-মেমরি ভেরিয়েন্ট রয়েছে, কিন্তু সেগুলি সেটআপ করতে সময় লাগে। রিপজিটরির পরিবর্তে Stub ডাটাবেস স্পর্শ না করে পূর্বপ্রস্তুত Entity তালিকা ফেরত দেয়। এটি বিশেষ করে ViewModel পরীক্ষার জন্য কার্যকর, যেখানে আপনাকে সর্টিং, ফিল্টারিং বা ডাটা রূপান্তর যাচাই করতে হবে। ডাটার পরিমাণ নির্বিশেষে পরীক্ষাটি মিলিসেকেন্ডে চলে।
সিস্টেম সার্ভিস — LocationManager, SensorManager, SharedPreferences এর জন্য একটি বাস্তব ডিভাইস বা এমুলেটর প্রয়োজন। LocationProvider এর জন্য Stub নির্দিষ্ট স্থানাংক ফেরত দেয়, SensorManager এর জন্য — এক্সেলেরোমিটারের নির্দিষ্ট মান। iOS এ, অ্যানালগ হল CLLocationManager একটি পরীক্ষণ ডিলিগেট বাস্তবায়ন সহ। স্টাব ছাড়া, এই পরীক্ষাগুলির জন্য নির্দিষ্ট সর্ত সহ একটি ভৌতিক ডিভাইস প্রয়োজন।
ফাইল সিস্টেম এবং ক্যাশ — ছবি লোডিং, প্রতিক্রিয়া ক্যাশিং, কনফিগরেশন ফাইলের সাথে কাজ — এই সব কাজ ডিস্কের অবস্থার উপর নির্ভর করে। FileManager বা ImageCache এর জন্য Stub বাস্তব ফাইল না পড়ে সফলতা/ব্যর্থতা ফেরত দেয়। এটি বিভিন্ন ডেভেলপার মশিনে পাথ অসামঞ্জস্য বা প্রবেশাধিকারের কারণে মিথ্যা পরীক্ষা ব্যর্থতা দূর করে।
দায়িত্বের বিভাজন — তিন ধরণের test doubles ভিন্ন কাজ সমাধান করে। Stub: «আমাকে ডাটা দাউ»। Mock: «যাচাই করো যে আমাকে ডাকা হয়েছে»। Fake: «আমি আসলের মতো কাজ করি, কেবল সরল»। পার্থক্যটি পরীক্ষা পড়ার যোগ্যতার জন্য গুরুত্বপূর্ণ: যদি একটি পরীক্ষা mock ব্যবহার করে যেখানে stub প্রয়োজন, তবে এটি পরীক্ষিত পরিদৃশ্যের সাথে অসম্পর্কিত verify কলে ভরা থাকে।
| বৈশিষ্ট্য | Stub | Mock | Fake |
|---|---|---|---|
| উদ্দেশ্য | ডাটা প্রদান | মিথস্থাপন যাচাই | সরল বাস্তবায়ন |
| যুক্তি | নেই | নেই | আছে (কিন্তু সরল) |
| যাচাই | নেই | হ্যাঁ (verify) | পরোক্ষ (অবস্থার মাধ্যমে) |
| নমনীয়তা | কম — নির্দিষ্ট উত্তর | মধ্যম | উচ্চ — যুক্তি খাপ খায় |
| গতি | সর্বোচ্চ | উচ্চ | মধ্যম |
| উদাহরণ | MockWebServer JSON ফেরত দেয় | Mockito.verify(repository).save() | HashMap সহ InMemoryRepository |
ব্যাবহারিক নিয়ম — যদি পরীক্ষাটি যাচাই করে যে পরীক্ষিত উপাদান কীড়েশন পেয়েছে — stub ব্যবহার করুন। যদি পরীক্ষাটি যাচাই করে যে উপাদানটি সঠিক আর্গুমেন্ট সহ নির্ভরতার মেথড ডেকেছে কিনা — mock ব্যবহার করুন। যদি আপনি শুধু একটি ডাটাবেসকে একটি হ্যাশ টেবল দিয়ে প্রতিস্থাপন করতে চান — এটি fake। একটি পরীক্ষায় ধরন মিশ্রাং করা এটিকে ভঙ্গুর করে: যখন বাস্তবায়ন পরিবর্তিত হয়, আপনাকে stub এবং verify উভয় যুক্তি পুনরায় লিখতে হবে।
verify সহ Stub — একটি সাধারণ ভুল যেখানে ডেভেলপার একটি stub সেটআপ করে এবং তারপর verify(stub).method() যোগ করে। Stub সংজ্ঞা অনুযায়ী এর যাচাই করা উচিত নয় — যাচাইর জন্য mock রয়েছে। যদি আপনাকে যাচাই করতে হবে যে একটি মেথড নির্দিষ্ট আর্গুমেন্ট সহ ডাকা হয়েছে, তবে Mockito.stub() এর পরিবর্তে Mockito.mock() ব্যবহার করুন। এই পৃথক্করণ অন্যান্য ডেভেলপারের জন্য পরীক্ষার উদ্দেশ্য স্পষ্ট রাখে।
MockWebServer — Android এবং JVM এ HTTP স্টাব তৈরির জন্য একটি OkHttp লাইব্রেরী। এটি একটি নির্দিষ্ট পোর্টে একটি লোকাল HTTP সরভার শুরু করে যা OkHttp ক্লায়েন্ট অনুরোধ আটকায় এবং পূর্বনির্ধারিত প্রতিক্রিয়া ফেরত দেয়। সেটআপ তিন লাইনে সম্পন্ন: সরভার তৈরি, প্রতিক্রিয়া enqueue, এটি শুরু। পরীক্ষাটি পেজিনেশন বা রিট্রি পরিদৃশ্যের জন্য ধারাবাহিকভাবে একাধিক প্রতিক্রিয়া enqueue করতে পারে।
class UserRepositoryTest {
private val server = MockWebServer()
fun setup() {
server.start(8080)
val client = OkHttpClient.Builder()
.readTimeout(1, TimeUnit.SECONDS)
.build()
}
fun test_user_list_success() {
val json = "[{\"id\":1,\"name\":\"Alice\"}]"
server.enqueue(MockResponse()
.setBody(json)
.setResponseCode(200)
)
val result = repository.getUsers()
assertEquals(1, result.size)
}
fun teardown() {
server.shutdown()
}
}
MockK — কোরুটিন, এক্সটেনশন ফাংকশন এবং সীলড ক্লাসের জন্য প্রথম শ্রেণীর সমর্থন সহ Kotlin এর জন্য Mockito এর একটি বিকল্প। MockK এ স্টাব coEvery (suspend ফাংকশনের জন্য) এবং every (নির্দিষ্ট ফাংকশনের জন্য) এর মাধ্যমে তৈরি করা হয়। MockWebServer থেকে ভিন্ন, MockK সম্পূর্ণ HTTP স্তরের পরিবর্তে পৃথক নির্ভরতা মেথড স্টাব করে। এটি UseCase বা Interactor এর ইউনিট টেস্টের জন্য সুবিধাজনক, যেখানে নির্ভরতাগুলি রিপজিটরি অ্যাবস্ট্রাকশন।
interface UserRepository {
suspend fun getUsers(): List<User>
}
class GetUsersUseCaseTest {
private val repo = mockk<UserRepository>()
private val useCase = GetUsersUseCase(repo)
fun test_empty_list() = runTest {
coEvery { repo.getUsers() } returns emptyList()
val result = useCase.invoke()
assertTrue(result.isEmpty())
coVerify(exactly = 1) { repo.getUsers() }
}
}
সর্বোত্তম অভ্যাস — ইন্টিগ্রেশন টেস্টের জন্য MockWebServer (বাস্তব HTTP আটকায়) ব্যবহার করুন, ইউনিট টেস্টের জন্য MockK (ইন্টারফেস স্টাব করে) ব্যবহার করুন। যা পরীক্ষা করছেন না তা স্টাব করবেন না: যদি পরীক্ষাটি Repository যাচাই করে, তবে এর মধ্যে OkHttp ক্লায়েন্ট স্টাব করবেন না — HTTP স্তরে একটি বাস্তব MockWebServer ব্যবহার করুন। এই নিয়ম পরীক্ষাগুলিকে প্রাসঙ্গিক রাখে এবং রিফাক্টরিং-এর সময় ভঙ্গুরতা হ্রাস করে।
Swift প্রোটোকল স্টাব হিসেবে — iOS-নেটিভ পদ্ধতিতে, stub বাস্তবায়ন করা হয় একটি পরীক্ষা গঠন প্রতিস্থাপন করে যা নির্ভরতা প্রোটোকল মেনে চলে। বাস্তব NetworkService এর পরিবর্তে, পরীক্ষাটি একটি StubNetworkService পেয় যা নির্দিষ্ট ডাটা ফেরত দেয়। Swift একটি স্থৈতিক টাইপের ভাষা, তাই stub কে বাস্তব পরিষেবার একই প্রোটোকল মেনে চলতে হবে। কম্পাইলার গারন্টি দেয় যে stub সকল প্রয়োজনীয় মেথড বাস্তবায়ন করে।
protocol NetworkServiceProtocol {
func fetchUsers() async throws -> [User]
}
struct StubNetworkService: NetworkServiceProtocol {
let result: Result<[User], Error>
func fetchUsers() async throws -> [User] {
try result.get()
}
}
final class UsersViewModelTests: XCTestCase {
func test_success_state() async {
let stub = StubNetworkService(
result: .success([User(name: "Alice")])
)
let vm = UsersViewModel(service: stub)
await vm.load()
XCTAssertEqual(vm.users.count, 1)
}
}
Objective-C এর জন্য OCMock — পুরাতন iOS প্রজেক্টে স্টাব এবং মক তৈরির জন্য একটি লাইব্রেরী। OCMock আর্গুমেন্ট এবং রিটার্ন ভ্যালিউ সহ স্টাব মেথড সমর্থন করে। আধুনিক Swift প্রজেক্ট ম্যানুয়াল স্টাব সহ প্রোটোকল-ভিত্তিক পদ্ধতি পছন্দ করে — এটি প্রতিটি মেথডের উপর নিয়ন্ত্রণ দেয় এবং বাহ্য নির্ভরতার প্রয়োজন হয় না। OCMock সেই প্রজেক্টগুলির জন্য একটি বিকল্প হিসেবে রয়েছে যেখানে সকল নির্ভরতা প্রোটোকলিকরণ আর্থিকভাবে সম্যক নয়।
HTTP স্টাবের জন্য URLProtocol — URLProtocol এর একটি উপবর্গের মাধ্যমে নেটওয়ার্ক অনুরোধ আটকানোর জন্য iOS এ একটি সিস্টম প্রক্রিয়া। পরীক্ষাটি একটি কাস্টম URLProtocol নিবন্ধিত করে যা URLSession আটকায় এবং স্টাব প্রতিক্রিয়া ফেরত দেয়। ম্যানুয়াল স্টাবের চেয়ে সুবিধা: আপনাকে অ্যাপ্লিকেশন আর্কিটেক্চার পরিবর্তন করতে হবে না — URLSession বাস্তবিক থাকে, কিন্তু ডাটা প্রোটোকল স্তরে প্রতিস্থাপিত হয়। ওপরেটি: স্পষ্ট stub সার্ভিসের চেয়ে ডিবাগ করা কঠিন।
সামান্য জিজ্ঞাসা
Stub পূর্বনির্ধারিত ডাটা ফেরত দেয় এবং কোনো কল হয়েছে কিনা তা যাচাই করে না। Mock অতিরিক্তভাবে যাচাই করে যে মেথডটি সঠিক আর্গুমেন্ট সহ ডাকা হয়েছে (verify)। Stub প্রশ্নের উত্তর দেয় «কী ফেরত দেবে», Mock উত্তর দেয় «কলটি হয়েছিল কি»। অবস্থা যাচাইর জন্য stub, মিথস্থাপন যাচাইর জন্য mock ব্যবহার করুন।
Fake প্রয়োজন যখন পরীক্ষার একটি কাজকর (যদিও সরল) বাস্তবায়ন প্রয়োজন — উদাহরণস্বরূপ, Room এর পরিবর্তে একটি ইন-মেমরি ডাটাবেস। Stub পূর্বনির্ধারিত ডাটা সহ একক পরিদৃশ্যের জন্য উপযুক্ত। যদি আপনি 10 টি পরীক্ষায় একই stub পুনরাবৃত্তি করছেন — সম্ভবতঃ আপনার Fake প্রয়োজন। Fake ডিউপ্লিকেশন কমায় কারণ যুক্তিটি একটি ক্লাসে বসবাস করে।
Android এ — MockK Kotlin অবজেক্ট (object) এর জন্য mockkObject() সমর্থন করে, যার মধ্যে mockkStatic() এর মাধ্যমে Java ক্লাসের স্টেটিক মেথড অন্তর্ভুক্ত। iOS এ — Swift স্টেটিক মেথড সরাসরি স্টাব করা যায় না; একটি প্রোটোকলের ইন্স্টেন্স মেথড দিয়ে স্টেটিক কল প্রতিস্থাপন করতে প্রোটোকল এবং DI ব্যবহার করুন। স্টেটিক স্টাব কারিগরি দায়িত্ব এবং নতুন কোডে এর পরিহার করা উচিত।
MockWebServer (OkHttp) ব্যবহার করুন — এটি একটি লোকাল HTTP সরভারের মতো কাজ করে যা প্রতিক্রিয়া enqueue করে। Retrofit এর জন্য, বেস URL টি localhost:8080 দিয়ে প্রতিস্থাপন করতে হবে। Ktor এর জন্য, MockEngine ব্যবহার করুন — HttpStatement প্রতিস্থাপনের জন্য একটি অন্নির্মিত প্রক্রিয়া। উভয় পদ্ধতি বাস্তব ইন্টারনেট ছাড়াই কাজ করে এবং স্টেটাস কোড, বড়ি এবং প্রতিক্রিয়া হেডারের উপর সম্পূর্ণ নিয়ন্ত্রণ দেয়।
Spy একটি বাস্তব অবজেক্টকে মোড়ে এবং কল রেকর্ড করে, যখন Stub নিশ্চিত প্রতিক্রিয়া দিয়ে অবজেক্টটিকে সম্পূর্ণ প্রতিস্থাপিত করে। Spy বাস্তব বাস্তবায়নের আংশিক ব্যবহারের অনুমতি দেয় (অন্যান্য মেথড যেমন ছিল তেমনি কাজ করে), যখন stub করে না। যদি আপনাকে যাচাই করতে হবে যে একটি মেথড ডাকা হয়েছে কিন্তু যুক্তির অংশ নিষ্পাদিত হলেও উচিত — stub নয়, spy ব্যবহার করুন।
সারাংশ
আমরা একটি মোবাইল অ্যাপ্লিকেশন টার্নকি তৈরি করব
IT Sectr 2017 সাল থেকে স্টার্টআপ এবং ব্যবসার জন্য iOS এবং Android অ্যাপ্লিকেশন তৈরি করে। আমরা আপনাকে পরামর্শ দেব এবং সেরা সমাধান প্রস্তাব করব।
আরও পড়ুন