Spy — এটি কি, Mockito.spy() এবং কল যাচাই

লেখক: IT Sectr প্রকাশিত: 2026-04-10 পড়ার সময়: 9 মিনিট

Spy (গুপ্তচর) — একটি পরীক্ষণ অবজেক্ট যা একটি বাস্তব ইন্স্টেন্সকে ঘেরাদায় করে এবং প্রতিটি কল সম্পর্কে তথ্য রেকর্ড করে: কোন মেথডগুলি ডাকা হয়েছিল, কি আর্গুমেন্ট দিয়ে, এবং কত বার। mock এর বিপরীতে, spy ঘেরানো অবজেক্টের বাস্তব বাস্তবায়ন ব্যবহার করে — কলগুলি বাস্তব কোড দিয়ে গিয়ে থাকে, এবং spy কেবল তথ্যগুলি রেকর্ড করে। পরীক্ষা শেষে, ডিভেলপার গুপ্তচরের রেকর্ড যাচাই করে: «sendAnalytics মেথডটি কি তিন বার ডাকা হয়েছিল?»। আরও জানতে Android পরীক্ষণ গাইড দেখুন।

মূখ্য বিষয়

  • Spy — এমন একটি অবজেক্ট যা প্রতিস্থাপন ছাড়াই বাস্তব বাস্তবায়নের মেথড কল রেকর্ড করে
  • যাচাই — পরীক্ষার পর, spy যাচাই করতে দেয় যে কত বার এবং কি আর্গুমেন্ট দিয়ে একটি মেথড ডাকা হয়েছিল
  • Mockito.spy() — বাস্তব Java/Kotlin অবজেক্টের জন্য Android এ গুপ্তচর তৈরি করে
  • আংশিক মকিং — spy কে stub এর সাথে সঙ্গীয় করা যেতে পারে: কিছু মেথড ইন্টারসেপ্ট করা, অন্যগুলিকে পার হতে দেওয়া
  • iOS — OCMock (Objective-C) এবং Swift এ প্রোটোকলের মাধ্যমে ম্যানুয়াল গুপ্তচর

Spy কি এবং এটি Mock হতে কিভাবে আলাদা?

Spy — একটি বাস্তব অবজেক্টের চারপাশে একটি র্যাপার যা সকল মেথড কল ইন্টারসেপ্ট করে এবং সেগুলি রেকর্ড করে। অবজেক্টের বাস্তব যুক্তি কার্যকর হয়: যদি মেথডটি ডেটা সংরক্ষণ করে, একটি মান গণনা করে, অথবা একটি অনুরোধ করে — সব সাধারণ ভাবে ঘটে। উপরোন্তিভাবে, spy মেটাডেটা রেকর্ড করে: মেথড নাম, আর্গুমেন্ট, কল সংখ্যা, কার্যকরণ সময়। শব্দটি Meszaros (2007) শ্রেণীবিভাগের অংশ এবং Martin Fowler এর নিবন্ধ «Mocks Aren’t Stubs» এ বিস্তারিতভাবে বর্ণিত।

Mock হতে মূল পার্থক্য — mock সম্পূর্ণরূপে অবজেক্টকে একটি পরীক্ষণ stub দিয়ে প্রতিস্থাপন করে; সকল মেথড ডিফল্টভাবে কিছুই করে না। spy একটি বিদ্যমান অবজেক্টকে ঘেরাদায় করে: সকল মেথড ডিফল্টভাবে সাধারণ মতো কাজ করে, কিন্তু সেগুলি আরও রেকর্ড করা হয়। এই পার্থক্যটি মৌলিক: mock পরীক্ষিত কোডকে বাস্তবতা হতে পৃথক করে, যখন spy বাস্তবতা সংরক্ষণ করে এবং এটি নিরীক্ষণ করার অনুমতি দেয়। তাদের মধ্যে পছন্দ কি পরীক্ষা করা হচ্ছে তার উপর নির্ভর করে।

কোন সময় Spy সঠিক পছন্দ

Spy সঠিক পছন্দ — যদি পরীক্ষিত কোড একটি বাস্তব অবজেক্টের অবস্থা পরিবর্তন করে, এবং পরীক্ষাকে ফলাফল (অবস্থা) যাচাই করতে হবে এবং নিশ্চিত করতে হবে যে কলগুলি সঠিক ক্রমে করা হয়েছিল। mock উপযুক্ত নয় কারণ এটি বাস্তব বাস্তবায়ন করে না। stub উপযুক্ত নয় কারণ এটি কল রেকর্ড করে না। Spy এই একমাত্র পরীক্ষণ ডবল যা একধারা বাস্তব যুক্তি সংরক্ষণ করে এবং কল সম্পর্কে তথ্য প্রদান করে।

Spy vs Mock: কোন সময় গুপ্তচর ব্যবহার করবেন

Mock — সম্পূর্ণ বিচ্ছিন্নতা. যদি পরীক্ষাটি বাস্তব অবজেক্টের বাস্তবায়নের উপর নির্ভর হউয়া উচিত নয় (যেমন, একটি ডেটাবেস অথবা নেটওয়ার্ক ক্লায়েন্ট), mock ব্যবহার করুন। mock নিশ্চিত করে যে কোনো কল বাস্তব উপাদানে পৌছায় না। এটি নিরাপদ এবং পূর্বানুমানযোগ্য। খারাপ দিক: mock বাস্তব যুক্তি কার্যকর করে না, তাই যদি পরীক্ষিত কোড একটি ফিরে আসা মানের উপর নির্ভর করে, তবে এটিকে when/stub এর মাধ্যমে স্পষ্টভাবে কনফিগার করতে হবে।

Spy — বাস্তব যুক্তি + পর্যবেক্ষণ. যদি পরীক্ষিত কোড এমন একটি অবজেক্টের সঙ্গে ইন্টারাক্ট করে যার যুক্তি পরীক্ষার জন্য গুরুত্বপূর্ণ, এবং শুধুমাত্র ডেটা নয় — spy ব্যবহার করুন। উদাহরণস্বরূপ, AnalyticsTracker যা ইভেন্ট সংগ্রহ করে এবং মঠিক পর্যায়ক্রমিকভাবে পাঠায়। পরীক্ষা যাচাই করে যে ইভেন্টগুলি বাফারে যোগ করা হয়েছিল, এবং পাঠানোর পর বাফার খালি হয়ে গিয়েছিল। mock এটি যাচাই করতে পারে না কারণ এটি ট্রেকারের বাস্তব যুক্তি কার্যকর করে না।

দৃশ্যSpyMock
বাস্তব যুক্তি প্রয়োজনহ্যাঁনা (stub)
কল যাচাইহ্যাঁ (সংখ্যা, আর্গুমেন্ট)হ্যাঁ (সংখ্যা, আর্গুমেন্ট)
আংশিক stubbingহ্যাঁ (কিছু মেথড spy, অন্যগুলি stub)না (সকল মেথড stub)
পার্শ্ব প্রতিক্রিয়ার ঝুঁকিউচ্চ (বাস্তব কোড)শূন্য
গতিকম (বাস্তব যুক্তি)বেশি (stub)
পড়ার সুবিধাকম (কোনটি বাস্তব তা বোঝা কঠিন)বেশি (সবকিছু স্পষ্ট)

অ্যান্টিপ্যাটার্ন: সবকিছুর জন্য spy

সবকিছুর জন্য spy — সকল পরীক্ষায় mock এর পরিবর্তে spy ব্যবহার করা একটি ভূল। spy বাস্তব কোড কার্যকর করে যার পার্শ্ব প্রতিক্রিয়া থাকতে পারে: ফাইলে লেখা, HTTP পাঠানো, গ্লোবাল অবস্থা পরিবর্তন। যদি পরীক্ষিত মডিউল একটি spy অবজেক্টের একটি মেথড ডাকে যা HTTP অনুরোধ করে, তবে পরীক্ষাটি একটি ইন্টিগ্রেশন পরীক্ষায় পরিণত হয়, ইউনিট পরীক্ষা নয়। নিয়ম: যদি spy I/O কাজগুলি সহ একটি অবজেক্টকে ঘেরাদায় করে — তবে এটি আর ইউনিট পরীক্ষা নয়। I/O আলাদা করতে mock ব্যবহার করুন, এবং spy কেবল বাহ্য প্রভাবহীন মেমরিতে রথাকা অবজেক্টের জন্য ব্যবহার করুন।

Android এ Mockito.spy() এবং MockK এ spy

Mockito.spy() — Java/Kotlin প্রকল্পে গুপ্তচর তৈরির ক্লাসিক উপায়। spy() একটি বাস্তব অবজেক্ট নেয় এবং একটি র্যাপার ফিরিয়ে দেয়। সকল কল ডিফল্টভাবে বাস্তব অবজেক্টে প্রতিনিধিত্ব করা হয়, এবং ফলাফল রেকর্ড করা হয়। পরীক্ষার পর, আপি কল সংখ্যা এবং আর্গুমেন্ট যাচাই করতে verify() ব্যবহার করতে পারেন। যে মেথডগুলি পরীক্ষার উপাদান ফিরিয়ে দেওয়া উচিত, সেগুলির জন্য doReturn/when ব্যবহার করা হয় — এটিকে «আংশিক মকিং» বলা হয়।

kotlin
class AnalyticsReporterTest {

    private val realTracker = AnalyticsTracker()
    private val spyTracker = Mockito.spy(realTracker)

    fun test_event_tracked() {
        val event = AnalyticsEvent("login")
        spyTracker.track(event)

        Mockito.verify(spyTracker).track(event)
        assertEquals(1, spyTracker.getBufferedCount())
    }

    fun test_track_with_exception() {
        Mockito.doThrow(RuntimeException("network"))
            .when(spyTracker).flush()

        spyTracker.track(AnalyticsEvent("login"))
        assertTrue(spyTracker.hasPendingEvents())
    }
}

MockK.spyk() — কোরুটিন এবং sealed ক্লাসের উন্নত সমর্থন সহ Kotlin প্রকল্পগুলির একটি বিকল্প। MockK.spyk() একটি গুপ্তচর তৈরি করে, যা Mockito.spy() এর অনুরূপ। এটি suspend ফাংকশনের জন্য coVerify এবং আংশিক stubbing এর জন্য every সমর্থন করে। Mockito এর বিপরীতে, MockK final ক্লাসের জন্য spy সমর্থন করে না (Kotlin এ সকল ক্লাস ডিফল্টভাবে final হয়) — আপনাকে ক্লাসটি খুলতে (open) বা ইন্টারফেস ব্যবহার করতে হবে।

kotlin
class LoginUseCaseTest {

    private val realRepo = UserRepository()
    private val spyRepo = spyk(realRepo)

    private val useCase = LoginUseCase(spyRepo)

    fun test_login_calls_save() = runTest {
        every { spyRepo.getUser(any()) } returns User("test")

        val result = useCase.login("test", "pass")

        coVerify { spyRepo.saveLoginTime(any()) }
        assertTrue(result.isSuccess)
    }
}

Spy এর মাধ্যমে আংশিক Stubbing

আংশিক stubbing — একটি শক্তিশালী কিন্তু বিপদপূর্ণ কৌশল। আপি একটি অবজেক্টের spy তৈরি করতে পারেন এবং শুধুমাত্র কিছু মেথড অভিভূত (stub) করতে পারেন, বাকিগুলি বাস্তব রেখে দিতে পারেন। উদাহরণ: একটি spy রিপজিটরি যেখানে getUser() পরীক্ষার উপাদান ফিরিয়ে দেয়, যখন saveUser() বাস্তবে একটি in-memory তালিকায় সংরক্ষণ করে। এটি stub (নিয়ন্ত্রিত উপাদান) এবং spy (বাস্তব যুক্তি) উভয়ের সুবিধা সম্মিলিত করার অনুমতি দেয়। খারাপ দিক: পরীক্ষার পড়ার সুবিধা খারাপ হয় — কোন মেথডগুলি বাস্তব এবং কোনগুলি stub তা স্পষ্ট নয়।

OCMock এবং প্রোটোকল সহ iOS এ Spy বাস্তবায়ন

Objective-C এর জন্য OCMock — একটি লাইব্রেরি যা niceMock এর মাধ্যমে spy অবজেক্ট তৈরির সমর্থন করে। OCMock Objective-C runtime ব্যবহার করে মেথড কল ইন্টারসেপ্ট করে এবং সেগুলি রেকর্ড করে। পরীক্ষার পর verify ডাকা হয়। OCMock যে কোনও অবজেক্টের জন্য spy সমর্থন করে (Objective-C এ সকল মেথড ডায়নামিক), যা Swift এর তুলনায় একটি সুবিধা, যেখানে spy কেবল প্রোটোকলের মাধ্যমেই সম্ভব।

objective-c
// একটি বাস্তব অবজেক্টের জন্য spy তৈরি
AnalyticsTracker *realTracker = [[AnalyticsTracker alloc] init];
AnalyticsTracker *spy = [OCMockObject partialMockForObject:realTracker];

// পরীক্ষা কার্যকরণ
[spy trackEvent:@"login"];

// যাচাই
[[spy verify] trackEvent:@"login"];
XCTAssertEqual([realTracker eventCount], 1);

Swift প্রোটোকল-ভিত্তিক spy — Swift এ Objective-C এর মতো runtime প্রতিফলন নেই, তাই spy ম্যানুয়ালি তৈরি করা হয়। একটি পরীক্ষণ গঠন একটি প্রোটোকল বাস্তবায়ন করে এবং আন্তরিকভাবে বাস্তব অবজেক্টকে ডাকার পাশাপাশি কল রেকর্ড করে। এর জন্য আরও কোড প্রয়োজন, কিন্তু এটি সম্পূর্ণরূপে নিয়ন্ত্রণযোগ্য এবং টাইপ-নিরাপদ। ম্যানুয়াল গুপ্তচরের বাহ্য লাইব্রেরির প্রয়োজন নেই এবং runtime ব্যবহার করে না — সব কিছু কম্পাইল সময় যাচাই করা হয়।

swift
protocol AnalyticsProtocol {
    func trackEvent(name: String)
}

final class SpyAnalytics: AnalyticsProtocol {
    private let real: AnalyticsProtocol
    private var events: [String] = []

    init(real: AnalyticsProtocol) {
        self.real = real
    }

    func trackEvent(name: String) {
        events.append(name)
        real.trackEvent(name: name)
    }

    func verifyTracked(name: String) -> Bool {
        return events.contains(name)
    }
}

কোন সময় OCMock বাম ম্যানুয়াল spy ব্যবহার করবেন — Objective-C কোডের জন্য OCMock ব্যবহার করুন (কম boilerplate)। Swift এর জন্য প্রোটোকলের মাধ্যমে ম্যানুয়াল গুপ্তচর পছন্দ করুন। একটি ম্যানুয়াল spy কল রেকর্ডিংএর উপর সম্পূর্ণ নিয়ন্ত্রণ দেয়, প্রতিফলনের প্রয়োজন নেই এবং মান ধরন (structs) এর সঙ্গে কাজ করে। একমাত্র খারাপ দিক: নতুন মেথড যোগ করার সময় আপনাকে spy ক্লাস কোড প্রোটোকলের সঙ্গে সিঙ্ক্রনাইজ করে রাখতে হবে।

Spy এর সাধারণ ব্যবহারের দৃশ্য

অ্যানালিটিক্স যাচাই — spy এর সবচেয়ে সাধারণ ব্যবহার ক্ষেত্র। প্রোডাক্শন কোডে, অ্যানালিটিক্স কল সাধারণত সাধারণত অ্যাপলিকেশন জুড়ে ছড়িয়ে থাকে: লগইন, লগআউট, ক্রয়, ত্রুটি। পরীক্ষা AnalyticsTracker এর একটি spy র্যাপার তৈরি করে, একটি দৃশ্য (লগইন, পণ্য দেখা, কার্টে যোগ, ক্রয়) কার্যকর করে, এবং যাচাই করে যে সকল প্রয়োজনীয় ইভেন্ট সঠিক ক্রমে পাঠানো হয়েছিল। mock উপযুক্ত নয় কারণ AnalyticsTracker এ বাফারিং এবং পাঠানোর যুক্তি রয়েছে।

টাইমার এবং শেডিউলার — Handler (Android) অথবা Timer (iOS) ব্যবহার করা কোড পরীক্ষা করা বস্তব সময়ের জন্য কঠিন। Scheduler এর একটি spy র্যাপার রেকর্ড করে কোন কাজগুলি নির্ধারিত করা হয়েছিল এবং কি বিলম্বে। পরীক্ষা বাস্তব Handler এর একটি spy তৈরি করে, একটি কাজ করে, এবং যাচাই করে যে Handler.postDelayed(runnable, delay) সঠিক বিলম্বে ডাকা হয়েছিল। বাস্তব কাজটি করা হয় না — spy কলটি ইন্টারসেপ্ট করে এবং রেকর্ড করে।

লগিং এবং ডিবাগ তথ্য — প্রোডাক্শনে, লগ নিষ্ক্রিয় অথবা ফাইলে লেখা হতে পারে। Logger এর একটি spy র্যাপার সকল বার্তা একটি in-memory তালিকায় রেকর্ড করে যা পরীক্ষা কার্যকরনের পর যাচাই করে। এটি কনসোল না ভরে ত্রুটিতে সঠিক বার্তা লেখা হয়েছে কিনা তা যাচাই করার অনুমতি দেয়। Logger এর জন্য ম্যানুয়াল গুপ্তচর iOS এ বিশেষ করে উপযোগী, যেখানে OSLog এর কোনো পরীক্ষণ API নেই।

কল ক্রম যাচাই — কিছু দৃশ্যের জন্য কাজগুলির কঠোর ক্রম প্রয়োজন: সংযোগ খুলুন, ডেটা পাঠান, সংযোগ বন্ধ করুন। Mockito InOrder.verify() এর মাধ্যমে ক্রম যাচাই করার অনুমতি দেয়। spy একই কাজ করে কিন্তু বাস্তব কার্যকরণ সংরক্ষণ করে। যদি ক্রম এবং প্রতিটি ধাপের ফলাফল (সংযোগটি বাস্তবে খুলেছিল) উভয়ই গুরুত্বপূর্ণ হয় — spy ব্যবহার করুন, mock নয়।

সামান্য জিজ্ঞাসা

Spy vs Mock: মূল পার্থক্য কি?

Spy একটি বাস্তব অবজেক্টকে ঘেরাদায় করে এবং তার যুক্তি কার্যকর করে, পাশাপাশি কল রেকর্ড করে। Mock সম্পূর্ণরূপে অবজেক্টকে একটি stub দিয়ে প্রতিস্থাপন করে — কোনো বাস্তব যুক্তি কার্যকর করা হয় না। spy আচরণ সংরক্ষণ করে, mock করে না। spy বাচুন যখন অবজেক্টের বাস্তব কাজ গুরুত্বপূর্ণ; mock বাচুন যখন আপনাকে পরীক্ষাকে বাহ্য নির্ভরতা হতে আলাদা করতে হবে।

কোন সময় Spy একটি খারাপ পছন্দ?

যখন spy র্যাপার বাস্তব I/O কাজের কারণ হয়। যদি spy এমন একটি অবজেক্টকে ঘেরাদায় করে যা ফাইলে লেখে, HTTP পাঠায়, অথবা ডিস্ক হতে পড়ে — পরীক্ষাটি আর ইউনিট পরীক্ষা নয়। দ্বিতীয় ক্ষেত্র: পরীক্ষা কেবল ফিরে আসা মান যাচাই করে কলে আগ্রহ ছাড়া — এখানে stub যথেষ্ট, এবং spy অতিরিক্ত। তৃতীয়: কোড spy এর অভ্যন্তরীণ অবস্থার উপর নির্ভর করে — এটি একটি ভঙ্গুর পরীক্ষা।

MockK কি spy সমর্থন করে?

হ্যাঁ, spyk() এর মাধ্যমে — Mockito.spy() এর সমান। MockK.spyk() একটি বাস্তব অবজেক্টের চারপাশে একটি গুপ্তচর তৈরি করে, আংশিক stubbing এর জন্য every এবং suspend ফাংকশনের জন্য coVerify/coroutinesVerify সমর্থন করে। সীমাবদ্ধতা: final ক্লাসের সঙ্গে কাজ করে না (open বা interface প্রয়োজন)। Java ক্লাসের জন্য, MockK spyk() ও সমর্থন করে কিন্তু @MockKJvmInline অ্যানোটেশন প্রয়োজন।

কি Mock থেকে Spy বানানো যায়?

প্রযুক্তিগতভাবে, না। Mock একটি stub যার কোনো বাস্তব বাস্তবায়ন নেই। Spy, সংজ্ঞা অনুযায়ী, একটি বাস্তব অবজেক্টকে ঘেরাদায় করে। Mockito এ, আপি mock কে spy এ পরিণত করতে পারেন না। কিন্তু আপি বিপরীটি করতে পারেন: একটি spy তৈরি করুন এবং doReturn/when (আংশিক mocking) এর মাধ্যমে কিছু মেথড অভিভূত করুন। এটি spy অবজেক্টের নির্বাচিত মেথডের জন্য mock এর অনুরূপ আচরণ দেয়।

Swift এ Spy কি প্রোটোকল আবশ্যক?

হ্যাঁ, আবশ্যক। Swift এ Java/Kotlin এর মতো গতিশীল প্রক্সিং নেই। spy ত₁রি করতে একটি প্রোটোকল প্রয়োজন যা উত্পাদন ক্লাস এবং spy ক্লাস উভয়ই বাস্তবায়ন করে। Swift প্রোটোকল-ভিত্তিক spy একটি ম্যানুয়াল বাস্তবায়ন যা একটি বাস্তব অবজেক্ট নেয়, তাকে কল দেয়, এবং মেটাডেটা রেকর্ড করে। বিকল্প: Cuckoo লাইব্রেরি, যা SourceKit এর মাধ্যমে spy ক্লাস জেনারেট করে।

সারাংশ

  • Spy — একটি বাস্তব অবজেক্টের চারপাশে একটি র্যাপার যা যুক্তি প্রতিস্থাপন ছাড়াই সকল মেথড কল রেকর্ড করে
  • Mock হতে পার্থক্য — spy বাস্তব কোড কার্যকর করে, mock একটি stub দিয়ে প্রতিস্থাপন করে
  • Mockito.spy() — Java/Kotlin এর জন্য, verify এবং partial mock সমর্থন সহ একটি বাস্তব অবজেক্টকে ঘেরাদায় করে
  • MockK.spyk() — কোরুটিন সমর্থন, sealed ক্লাস এবং coVerify সহ Kotlin সমতুল্য
  • iOS — Objective-C এর জন্য OCMock, Swift এর জন্য ম্যানুয়াল প্রোটোকল-ভিত্তিক spy
  • প্রধান দৃশ্য — অ্যানালিটিক্স যাচাই, টাইমার, লগ এবং কল ক্রম যাচাই
  • সাবধান — I/O কাজের সহ spy ইউনিট পরীক্ষাকে ইন্টিগ্রেশন পরীক্ষায় রূপান্তর করে

আমরা একটি মোবাইল অ্যাপ্লিকেশন টার্নকি তৈরি করব

IT Sectr 2017 সাল থেকে স্টার্টআপ এবং ব্যবসার জন্য iOS এবং Android অ্যাপ্লিকেশন তৈরি করে। আমরা আপনাকে পরামর্শ দেব এবং সেরা সমাধান প্রস্তাব করব।

প্রকল্প নিয়ে আলোচনা করুন

আরও পড়ুন