Hilt টেস্টিং গাইড

Hilt-এর মতো ডিপেন্ডেন্সি ইনজেকশন ফ্রেমওয়ার্ক ব্যবহার করার একটি সুবিধা হল যে এটি আপনার কোড পরীক্ষা করা সহজ করে তোলে।

ইউনিট টেস্ট

ইউনিট টেস্টের জন্য Hilt-এর প্রয়োজন নেই, কারণ কন্সট্রাক্টর ইনজেকশন ব্যবহার করে এমন ক্লাস টেস্ট করার সময়, সেই ক্লাস ইনস্ট্যান্টিয়েট করার জন্য আপনাকে Hilt ব্যবহার করতে হবে না। পরিবর্তে, আপনি সরাসরি একটি ক্লাস কনস্ট্রাক্টরকে কল করতে পারেন, ফেক বা মক ডিপেন্ডেন্সি পাস করে, ঠিক যেমন আপনি কনস্ট্রাক্টর অ্যানোটেট না করা থাকলে করতেন:

@ActivityScoped
class AnalyticsAdapter @Inject constructor(
  private val service: AnalyticsService
) { ... }

class AnalyticsAdapterTest {

  @Test
  fun `Happy path`() {
    // You don't need Hilt to create an instance of AnalyticsAdapter.
    // You can pass a fake or mock AnalyticsService.
    val adapter = AnalyticsAdapter(fakeAnalyticsService)
    assertEquals(...)
  }
}

আপনার কম্পোজেবলে hiltViewModel() কল করে পাওয়া ViewModel ক্লাসের ক্ষেত্রেও একই কথা প্রযোজ্য। ইউনিট টেস্টে, সরাসরি ফেক দিয়ে ViewModel তৈরি করুন। ViewModel থেকে কম্পোজেবলে স্টেট কীভাবে ফ্লো করে সেই সম্পর্কে জানতে, স্টেট ও Jetpack Compose এবং স্টেট কোথায় হোস্ট করতে হবে দেখুন।

এন্ড-টু-এন্ড টেস্ট

ইন্টিগ্রেশন টেস্টের জন্য, Hilt আপনার প্রোডাকশন কোডের মতোই ডিপেন্ডেন্সি ইনজেক্ট করে। Hilt-এর মাধ্যমে পরীক্ষা করার জন্য কোনও রক্ষণাবেক্ষণের প্রয়োজন হয় না কারণ Hilt অটোমেটিক প্রতিটি পরীক্ষার জন্য কম্পোনেন্টের একটি নতুন সেট তৈরি করে।

টেস্টিং ডিপেন্ডেন্সি যোগ করা হচ্ছে

আপনার টেস্টে Hilt ব্যবহার করতে, আপনার প্রোজেক্টে hilt-android-testing ডিপেন্ডেন্সি অন্তর্ভুক্ত করুন:

dependencies {
    // For Robolectric tests.
    testImplementation("com.google.dagger:hilt-android-testing:2.57.1")
    kspTest("com.google.dagger:hilt-android-compiler:2.57.1")

    // For instrumented tests.
    androidTestImplementation("com.google.dagger:hilt-android-testing:2.57.1")
    kspAndroidTest("com.google.dagger:hilt-android-compiler:2.57.1")

    // Compose UI test rule.
    androidTestImplementation("androidx.compose.ui:ui-test-junit4")
    debugImplementation("androidx.compose.ui:ui-test-manifest")

}

UI টেস্ট সেট-আপ

@HiltAndroidTest-এর সাথে Hilt ব্যবহার করে এমন যেকোনও UI টেস্ট আপনাকে অ্যানোটেট করতে হবে। এই অ্যানোটেশন প্রতিটি টেস্টের জন্য Hilt কম্পোনেন্ট তৈরি করার জন্য দায়ী।

এছাড়াও, আপনাকে টেস্ট ক্লাসে HiltAndroidRule যোগ করতে হবে। এটি কম্পোনেন্টের স্ট্যাটাস ম্যানেজ করে এবং আপনার টেস্টে ইনজেকশন পারফর্ম করতে ব্যবহার করা হয়:

@HiltAndroidTest
class SettingsScreenTest {

    @get:Rule(order = 0)
    val hiltRule = HiltAndroidRule(this)

    @get:Rule(order = 1)
    val composeRule = createAndroidComposeRule<HiltTestActivity>()

    // Compose UI tests here.
}

এরপর, আপনার টেস্টকে Application ক্লাস সম্পর্কে জানতে হবে যা Hilt আপনার জন্য অটোমেটিক তৈরি করে।

Hilt-কে ডিপেন্ডেন্সি ইনজেক্ট করতে দেওয়ার জন্য, আপনাকে androidTest সোর্স সেটে HiltTestActivity নামের একটি খালি অ্যাক্টিভিটি তৈরি করতে হবে এবং @AndroidEntryPoint দিয়ে এটিকে অ্যানোটেট করতে হবে। createAndroidComposeRule তারপর এই অ্যাক্টিভিটি আপনার কম্পোজেবল কন্টেন্টের হোস্ট হিসেবে ব্যবহার করে।

অ্যাপ্লিকেশন টেস্ট করুন

আপনাকে অবশ্যই এমন একটি Application অবজেক্টে Hilt ব্যবহার করে এমন ইন্সট্রুমেন্টেড টেস্ট চালাতে হবে যা Hilt-কে সাপোর্ট করে। লাইব্রেরি টেস্টে ব্যবহারের জন্য HiltTestApplication প্রদান করে। আপনার পরীক্ষার জন্য অন্য কোনও বেস অ্যাপ্লিকেশনের প্রয়োজন হলে, পরীক্ষার জন্য কাস্টম অ্যাপ্লিকেশন দেখুন।

আপনার ইনস্ট্রুমেন্টেড টেস্ট বা Robolectric টেস্ট-এ রান করার জন্য আপনার টেস্ট অ্যাপ্লিকেশন সেট করতে হবে। নিম্নলিখিত নির্দেশাবলী Hilt-এর জন্য নির্দিষ্ট নয়, তবে টেস্টে রান করার জন্য কীভাবে কাস্টম অ্যাপ্লিকেশন নির্দিষ্ট করতে হয় তার সাধারণ নির্দেশিকা।

ইনস্ট্রুমেন্টেড টেস্টে টেস্ট অ্যাপ্লিকেশন সেট করুন

ইনস্ট্রুমেন্টেড টেস্টে Hilt টেস্ট অ্যাপ্লিকেশন ব্যবহার করতে, আপনাকে একটি নতুন টেস্ট রানার কনফিগার করতে হবে। এটি আপনার প্রোজেক্টের সব ইনস্ট্রুমেন্টেড টেস্টের জন্য Hilt-কে কাজ করতে দেয়। নিম্নলিখিত ধাপগুলি অনুসরণ করুন:

  1. androidTest ফোল্ডারে AndroidJUnitRunner এক্সটেন্ড করে এমন কাস্টম ক্লাস তৈরি করুন।
  2. newApplication ফাংশন ওভাররাইড করুন এবং তৈরি করা Hilt টেস্ট অ্যাপ্লিকেশনের নাম পাস করুন।
// A custom runner to set up the instrumented application class for tests.
class CustomTestRunner : AndroidJUnitRunner() {

    override fun newApplication(cl: ClassLoader?, name: String?, context: Context?): Application {
        return super.newApplication(cl, HiltTestApplication::class.java.name, context)
    }
}

এরপর, ইনস্ট্রুমেন্টেড ইউনিট টেস্ট গাইড-এ যেভাবে বর্ণনা করা হয়েছে সেই অনুযায়ী আপনার Gradle ফাইলে এই টেস্ট রানার কনফিগার করুন। আপনি সম্পূর্ণ ক্লাসপাথ ব্যবহার করছেন কিনা তা নিশ্চিত করুন:

android {
    defaultConfig {
        // Replace com.example.android.dagger with your class path.
        testInstrumentationRunner = "com.example.android.dagger.CustomTestRunner"
    }
}
Robolectric টেস্টে টেস্ট অ্যাপ্লিকেশন সেট করুন

আপনার UI লেয়ার পরীক্ষা করার জন্য Robolectric ব্যবহার করলে, robolectric.properties ফাইলে কোন অ্যাপ্লিকেশন ব্যবহার করতে হবে তা আপনি নির্দিষ্ট করতে পারবেন:

application = dagger.hilt.android.testing.HiltTestApplication

বিকল্পভাবে, আপনি Robolectric-এর @Config অ্যানোটেশন ব্যবহার করে প্রতিটি টেস্টে আলাদাভাবে অ্যাপ্লিকেশন কনফিগার করতে পারেন:

@HiltAndroidTest
@Config(application = HiltTestApplication::class)
class SettingsScreenTest {

  @get:Rule
  var hiltRule = HiltAndroidRule(this)

  // Robolectric tests here.
}

ফিচার পরীক্ষা করা

আপনার টেস্টে Hilt ব্যবহার করার জন্য রেডি হয়ে গেলে, আপনি টেস্টিং প্রসেস কাস্টমাইজ করতে বিভিন্ন ফিচার ব্যবহার করতে পারবেন।

পরীক্ষায় ইনজেক্টের ধরন

কোনও টেস্টে টাইপ ইনজেক্ট করতে, ফিল্ড ইনজেকশনের জন্য @Inject ব্যবহার করুন। Hilt-কে @Inject ফিল্ড পূরণ করতে বলতে, hiltRule.inject() কল করুন।

ইনস্ট্রুমেন্টেড টেস্টের নিম্নলিখিত উদাহরণ দেখুন:

@HiltAndroidTest
class SettingsScreenTest {

    @get:Rule(order = 0)
    val hiltRule = HiltAndroidRule(this)

    @get:Rule(order = 1)
    val composeRule = createAndroidComposeRule<HiltTestActivity>()

    @Inject
    lateinit var analyticsAdapter: AnalyticsAdapter

    @Before
    fun init() {
        hiltRule.inject()
    }

    @Test
    fun settingsScreen_showsTitle() {
        composeRule.setContent {
            SettingsScreen()
        }
        composeRule.onNodeWithText("Settings").assertIsDisplayed()
        // analyticsRepository is available here.
    }
}

বাইন্ডিং পরিবর্তন করা

আপনাকে যদি কোনও ডিপেন্ডেন্সির ফেক বা মক ইনস্ট্যান্স ইনজেক্ট করতে হয়, তাহলে আপনাকে Hilt-কে বলতে হবে যাতে এটি প্রোডাকশন কোডে ব্যবহার করা বাইন্ডিং ব্যবহার না করে এবং এর পরিবর্তে অন্য একটি ব্যবহার করে। বাইন্ডিং পরিবর্তন করতে, আপনাকে সেই মডিউলটি পরিবর্তন করতে হবে যেটিতে টেস্ট মডিউলের সাথে বাইন্ডিং রয়েছে, যাতে আপনি টেস্টে যে বাইন্ডিং ব্যবহার করতে চান তা রয়েছে।

যেমন, ধরুন আপনার প্রোডাকশন কোড AnalyticsService-এর জন্য এইভাবে বাইন্ডিং ঘোষণা করে:

@Module
@InstallIn(SingletonComponent::class)
abstract class AnalyticsModule {

  @Singleton
  @Binds
  abstract fun bindAnalyticsService(
    analyticsServiceImpl: AnalyticsServiceImpl
  ): AnalyticsService
}

পরীক্ষায় AnalyticsService বাইন্ডিং পরিবর্তন করতে, test বা androidTest ফোল্ডারে ফেক ডিপেন্ডেন্সি সহ নতুন Hilt মডিউল তৈরি করুন এবং @TestInstallIn দিয়ে অ্যানোটেট করুন। পরিবর্তে, সেই ফোল্ডারের সব টেস্টে ফেক ডিপেন্ডেন্সি ইনজেক্ট করা হয়।

@Module
@TestInstallIn(
    components = [SingletonComponent::class],
    replaces = [AnalyticsModule::class]
)
abstract class FakeAnalyticsModule {

  @Singleton
  @Binds
  abstract fun bindAnalyticsService(
    fakeAnalyticsService: FakeAnalyticsService
  ): AnalyticsService
}

কারণ কম্পোজেবল সাধারণত hiltViewModel()-এর মাধ্যমে পাওয়া ViewModel-এর মাধ্যমে পরোক্ষভাবে এই ডিপেন্ডেন্সি ব্যবহার করে, তাই Hilt-এ বাইন্ডিং পরিবর্তন করাই যথেষ্ট। টেস্টের অধীনে থাকা কম্পোজেবল অটোমেটিক ফেক বেছে নেয়।

একটি টেস্টে বাইন্ডিং পরিবর্তন করুন

সব টেস্টের পরিবর্তে একটি টেস্টে বাইন্ডিং পরিবর্তন করতে, @UninstallModules অ্যানোটেশন ব্যবহার করে টেস্ট থেকে Hilt মডিউল আনইনস্টল করুন এবং টেস্টের মধ্যে নতুন টেস্ট মডিউল তৈরি করুন।

আগের ভার্সনের AnalyticsService উদাহরণ অনুসরণ করে, টেস্ট ক্লাসে @UninstallModules অ্যানোটেশন ব্যবহার করে প্রোডাকশন মডিউল উপেক্ষা করার জন্য Hilt-কে বলে শুরু করুন:

@UninstallModules(AnalyticsModule::class)
@HiltAndroidTest
class SettingsScreenTest { ... }

এরপর, আপনাকে বাইন্ডিং পরিবর্তন করতে হবে। টেস্ট ক্লাসের মধ্যে নতুন মডিউল তৈরি করুন যা টেস্ট বাইন্ডিংকে সংজ্ঞায়িত করে:

@UninstallModules(AnalyticsModule::class)
@HiltAndroidTest
class SettingsScreenTest {

  @Module
  @InstallIn(SingletonComponent::class)
  abstract class TestModule {

    @Singleton
    @Binds
    abstract fun bindAnalyticsService(
      fakeAnalyticsService: FakeAnalyticsService
    ): AnalyticsService
  }

  // ...
}

এটি শুধুমাত্র একটি টেস্ট ক্লাসের জন্য বাইন্ডিং পরিবর্তন করে। আপনি সব টেস্ট ক্লাসের জন্য বাইন্ডিং পরিবর্তন করতে চাইলে, উপরের বিভাগ থেকে @TestInstallIn অ্যানোটেশন ব্যবহার করুন। এছাড়াও, আপনি Robolectric টেস্টের জন্য test মডিউলে অথবা ইন্সট্রুমেন্টেড টেস্টের জন্য androidTest মডিউলে টেস্ট বাইন্ডিং রাখতে পারেন। সম্ভব হলে @TestInstallIn ব্যবহার করার সাজেশন দেওয়া হয়।

নতুন ভ্যালু বাইন্ড করা হচ্ছে

Hilt ডিপেন্ডেন্সি গ্রাফে আপনার টেস্টের ফিল্ড সহজে বাইন্ড করতে @BindValue অ্যানোটেশন ব্যবহার করুন। @BindValue দিয়ে কোনও ফিল্ড অ্যানোটেট করুন এবং এটি সেই ফিল্ডের জন্য উপস্থিত যেকোনও কোয়ালিফায়ারের সাথে ঘোষিত ফিল্ডের ধরনের অধীনে আবদ্ধ থাকবে।

AnalyticsService উদাহরণে, আপনি @BindValue ব্যবহার করে AnalyticsService-এর জায়গায় একটি ফেক ব্যবহার করতে পারেন:

@UninstallModules(AnalyticsModule::class)
@HiltAndroidTest
class SettingsScreenTest {

  @BindValue @JvmField
  val analyticsService: AnalyticsService = FakeAnalyticsService()

  ...
}

এটি আপনার টেস্টে বাইন্ডিং রিপ্লেস করা এবং বাইন্ডিং রেফারেন্স করা, দুটি কাজই সহজ করে তোলে কারণ আপনি একই সাথে দুটি কাজই করতে পারবেন।

@BindValue কোয়ালিফায়ার ও অন্যান্য টেস্টিং অ্যানোটেশনের সাথে কাজ করে। যেমন, আপনি যদি Mockito-এর মতো টেস্টিং লাইব্রেরি ব্যবহার করেন, তাহলে আপনি এটি Robolectric টেস্টে নিম্নলিখিত উপায়ে ব্যবহার করতে পারেন:

...
class SettingsScreenTest {
  ...

  @BindValue @ExampleQualifier @Mock
  lateinit var qualifiedVariable: ExampleCustomType

  // Robolectric tests here
}

আপনাকে যদি মাল্টিবাইন্ডিং যোগ করতে হয়, তাহলে আপনি @BindValue-এর জায়গায় @BindValueIntoSet এবং @BindValueIntoMap অ্যানোটেশন ব্যবহার করতে পারবেন। @BindValueIntoMap-এর জন্য আপনাকে ম্যাপ কী অ্যানোটেশন সহ ফিল্ড অ্যানোটেট করতে হবে।

বিশেষ মামলা

Hilt-এ এমন ফিচারও আছে যা নন-স্ট্যান্ডার্ড ব্যবহারের ক্ষেত্রে সাহায্য করে।

পরীক্ষার জন্য কাস্টম অ্যাপ্লিকেশন

আপনার টেস্ট অ্যাপ্লিকেশনকে অন্য অ্যাপ্লিকেশন এক্সটেন্ড করতে হবে বলে আপনি HiltTestApplication ব্যবহার করতে না পারলে, @CustomTestApplication-এর সাথে নতুন ক্লাস বা ইন্টারফেস অ্যানোটেট করুন, জেনারেট করা Hilt অ্যাপ্লিকেশনকে আপনি যে মূল ক্লাস এক্সটেন্ড করাতে চান সেটির ভ্যালু পাস করুন।

@CustomTestApplication, Hilt-এর সাথে টেস্ট করার জন্য প্রস্তুত একটি Application ক্লাস জেনারেট করবে যা প্যারামিটার হিসেবে আপনার পাস করা অ্যাপ্লিকেশনকে এক্সটেন্ড করে।

@CustomTestApplication(BaseApplication::class)
interface HiltTestApplication

উদাহরণে, Hilt Application নামের একটি HiltTestApplication_Application জেনারেট করে যা BaseApplication ক্লাসকে এক্সটেন্ড করে। সাধারণত, জেনারেট করা অ্যাপ্লিকেশনের নাম হল _Application-এর সাথে যুক্ত করা অ্যানোটেটেড ক্লাসের নাম। টেস্ট অ্যাপ্লিকেশন-এ যেভাবে বর্ণনা করা হয়েছে সেই অনুযায়ী, আপনার ইনস্ট্রুমেন্টেড টেস্ট বা Robolectric টেস্ট-এ রান করার জন্য আপনাকে অবশ্যই জেনারেট করা Hilt টেস্ট অ্যাপ্লিকেশন সেট করতে হবে।

আপনার ইনস্ট্রুমেন্টেড টেস্টে একাধিক TestRule অবজেক্ট আছে

Compose UI টেস্টে আগে থেকেই HiltAndroidRule-এর সাথে Compose টেস্ট রুল যেমন createAndroidComposeRule যোগ করা থাকে। আপনার কাছে অতিরিক্ত TestRule অবজেক্ট থাকলে, HiltAndroidRule প্রথমে রান করছে কিনা তা ভালো করে দেখে নিন। @Rule-এ order অ্যাট্রিবিউটের সাথে এক্সিকিউশন অর্ডার ঘোষণা করুন:

@HiltAndroidTest
class SettingsScreenTest {

  @get:Rule(order = 0)
  var hiltRule = HiltAndroidRule(this)

  @get:Rule(order = 1)
  val composeRule = createAndroidComposeRule<HiltTestActivity>()

  @get:Rule(order = 2)
  val otherRule = SomeOtherRule()

  // UI tests here.
}

বিকল্প হিসেবে, আপনি RuleChain-এর সাথে নিয়মগুলি র‍্যাপ করতে পারেন, যেখানে HiltAndroidRule-কে বাইরের নিয়ম হিসেবে রাখতে পারেন।

@HiltAndroidTest
class SettingsScreenTest {

  @get:Rule
  var rule = RuleChain.outerRule(HiltAndroidRule(this)).
        around(SettingsScreenTestRule(...))

  // UI tests here.
}

সিঙ্গলটন কম্পোনেন্ট উপলভ্য হওয়ার আগে একটি এন্ট্রি পয়েন্ট ব্যবহার করুন

@EarlyEntryPoint অ্যানোটেশন একটি এস্কেপ হ্যাচ প্রদান করে যখন একটি হিল্ট টেস্টে সিঙ্গলটন কম্পোনেন্ট উপলভ্য হওয়ার আগে একটি হিল্ট এন্ট্রি পয়েন্ট তৈরি করতে হয়।

@EarlyEntryPoint সম্পর্কে আরও তথ্য Hilt ডকুমেন্টেশনে আছে।

অতিরিক্ত রিসোর্স

পরীক্ষা করার ব্যাপারে আরও জানতে, নিম্নলিখিত অতিরিক্ত রিসোর্স দেখুন:

ডকুমেন্টেশন

কন্টেন্ট দেখে