یکی از مزایای استفاده از چارچوبهای تزریق وابستگی مانند 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(...) } }
جاوا
@ActivityScope public class AnalyticsAdapter { private final AnalyticsService analyticsService; @Inject AnalyticsAdapter(AnalyticsService analyticsService) { this.analyticsService = analyticsService; } } public final class AnalyticsAdapterTest { @Test public void happyPath() { // You don't need Hilt to create an instance of AnalyticsAdapter. // You can pass a fake or mock AnalyticsService. AnalyticsAdapter adapter = new AnalyticsAdapter(fakeAnalyticsService); assertEquals(...); } }
تست های پایان به انتها
برای تست های یکپارچه سازی، Hilt وابستگی ها را همانطور که در کد تولید شما اعمال می کند، تزریق می کند. آزمایش با Hilt نیازی به تعمیر و نگهداری ندارد زیرا Hilt به طور خودکار مجموعه جدیدی از مؤلفه ها را برای هر آزمایش تولید می کند.
افزودن وابستگی های آزمایشی
برای استفاده از Hilt در تستهای خود، وابستگی hilt-android-testing
را در پروژه خود بگنجانید:
شیار
dependencies { // For Robolectric tests. testImplementation 'com.google.dagger:hilt-android-testing:2.51.1' // ...with Kotlin. kaptTest 'com.google.dagger:hilt-android-compiler:2.51.1' // ...with Java. testAnnotationProcessor 'com.google.dagger:hilt-android-compiler:2.51.1' // For instrumented tests. androidTestImplementation 'com.google.dagger:hilt-android-testing:2.51.1' // ...with Kotlin. kaptAndroidTest 'com.google.dagger:hilt-android-compiler:2.51.1' // ...with Java. androidTestAnnotationProcessor 'com.google.dagger:hilt-android-compiler:2.51.1' }
کاتلین
dependencies { // For Robolectric tests. testImplementation("com.google.dagger:hilt-android-testing:2.51.1") // ...with Kotlin. kaptTest("com.google.dagger:hilt-android-compiler:2.51.1") // ...with Java. testAnnotationProcessor("com.google.dagger:hilt-android-compiler:2.51.1") // For instrumented tests. androidTestImplementation("com.google.dagger:hilt-android-testing:2.51.1") // ...with Kotlin. kaptAndroidTest("com.google.dagger:hilt-android-compiler:2.51.1") // ...with Java. androidTestAnnotationProcessor("com.google.dagger:hilt-android-compiler:2.51.1") }
راه اندازی تست رابط کاربری
شما باید هر تست رابط کاربری که از Hilt استفاده می کند با @HiltAndroidTest
حاشیه نویسی کنید. این حاشیه نویسی مسئول تولید اجزای Hilt برای هر تست است.
همچنین، باید HiltAndroidRule
را به کلاس تست اضافه کنید. وضعیت اجزا را مدیریت می کند و برای انجام تزریق در تست شما استفاده می شود:
کاتلین
@HiltAndroidTest class SettingsActivityTest { @get:Rule var hiltRule = HiltAndroidRule(this) // UI tests here. }
جاوا
@HiltAndroidTest public final class SettingsActivityTest { @Rule public HiltAndroidRule hiltRule = new HiltAndroidRule(this); // UI tests here. }
در مرحله بعد، آزمون شما باید در مورد کلاس Application
که Hilt به طور خودکار برای شما تولید می کند، بداند.
نرم افزار تست
شما باید تست های ابزاری را اجرا کنید که از Hilt در یک شی Application
که از Hilt پشتیبانی می کند استفاده می کند. این کتابخانه HiltTestApplication
برای استفاده در تست ها ارائه می دهد. اگر آزمونهای شما به برنامه پایه دیگری نیاز دارند، به برنامه سفارشی برای آزمایشها مراجعه کنید.
شما باید برنامه آزمایشی خود را طوری تنظیم کنید که در تست های ابزاری یا روبولکتریک شما اجرا شود. دستورالعملهای زیر مختص Hilt نیستند، اما دستورالعملهای کلی در مورد نحوه تعیین یک برنامه سفارشی برای اجرا در آزمایشها هستند.
برنامه آزمون را در تست های ابزار دقیق تنظیم کنید
برای استفاده از برنامه تست Hilt در تست های ابزاردار ، باید یک تست رانر جدید پیکربندی کنید. این باعث می شود که Hilt برای تمام تست های ابزاری در پروژه شما کار کند. مراحل زیر را انجام دهید:
- یک کلاس سفارشی ایجاد کنید که
AndroidJUnitRunner
در پوشهandroidTest
گسترش دهد. - تابع
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) } }
جاوا
// A custom runner to set up the instrumented application class for tests. public final class CustomTestRunner extends AndroidJUnitRunner { @Override public Application newApplication(ClassLoader cl, String className, Context context) throws ClassNotFoundException, IllegalAccessException, InstantiationException { return super.newApplication(cl, HiltTestApplication.class.getName(), context); } }
سپس، این تست رانر را در فایل Gradle خود پیکربندی کنید، همانطور که در راهنمای تست واحد ابزار دقیق توضیح داده شده است. مطمئن شوید که از classpath کامل استفاده می کنید:
شیار
android { defaultConfig { // Replace com.example.android.dagger with your class path. testInstrumentationRunner "com.example.android.dagger.CustomTestRunner" } }
کاتلین
android { defaultConfig { // Replace com.example.android.dagger with your class path. testInstrumentationRunner = "com.example.android.dagger.CustomTestRunner" } }
برنامه تست را در تست های روبولکتریک تنظیم کنید
اگر از Robolectric برای آزمایش لایه UI خود استفاده می کنید، می توانید مشخص کنید که از کدام برنامه در فایل robolectric.properties
استفاده کنید:
application = dagger.hilt.android.testing.HiltTestApplication
همچنین، میتوانید با استفاده از حاشیهنویسی @Config
Robolectric، برنامه را در هر آزمون بهصورت جداگانه پیکربندی کنید:
کاتلین
@HiltAndroidTest @Config(application = HiltTestApplication::class) class SettingsActivityTest { @get:Rule var hiltRule = HiltAndroidRule(this) // Robolectric tests here. }
جاوا
@HiltAndroidTest @Config(application = HiltTestApplication.class) class SettingsActivityTest { @Rule public HiltAndroidRule hiltRule = new HiltAndroidRule(this); // Robolectric tests here. }
اگر از نسخه Android Gradle Plugin پایینتر از 4.2 استفاده میکنید، با اعمال پیکربندی زیر در فایل build.gradle
ماژول، تبدیل کلاسهای @AndroidEntryPoint
را در تستهای واحد محلی فعال کنید:
شیار
hilt { enableTransformForLocalTests = true }
کاتلین
hilt { enableTransformForLocalTests = true }
اطلاعات بیشتر در مورد enableTransformForLocalTests
در مستندات Hilt .
ویژگی های تست
هنگامی که Hilt آماده استفاده در تست های شما شد، می توانید از چندین ویژگی برای سفارشی کردن فرآیند تست استفاده کنید.
انواع تزریق در آزمایشات
برای تزریق انواع به یک تست، از @Inject
برای تزریق فیلد استفاده کنید. برای اینکه به Hilt بگویید فیلدهای @Inject
را پر کند، hiltRule.inject()
را فراخوانی کنید.
نمونه زیر از یک تست ابزاری را ببینید:
کاتلین
@HiltAndroidTest class SettingsActivityTest { @get:Rule var hiltRule = HiltAndroidRule(this) @Inject lateinit var analyticsAdapter: AnalyticsAdapter @Before fun init() { hiltRule.inject() } @Test fun `happy path`() { // Can already use analyticsAdapter here. } }
جاوا
@HiltAndroidTest public final class SettingsActivityTest { @Rule public HiltAndroidRule hiltRule = new HiltAndroidRule(this); @Inject AnalyticsAdapter analyticsAdapter; @Before public void init() { hiltRule.inject(); } @Test public void happyPath() { // Can already use analyticsAdapter here. } }
یک صحافی را جایگزین کنید
اگر نیاز به تزریق یک نمونه جعلی یا ساختگی از یک وابستگی دارید، باید به Hilt بگویید که از اتصالی که در کد تولید استفاده کرده است استفاده نکند و به جای آن از یکی دیگر استفاده کند. برای جایگزینی یک صحافی، باید ماژول حاوی صحافی را با یک ماژول تست که حاوی اتصالاتی است که می خواهید در آزمون استفاده کنید، جایگزین کنید.
به عنوان مثال، فرض کنید کد تولید شما یک الزام آور برای AnalyticsService
به شرح زیر اعلام می کند:
کاتلین
@Module @InstallIn(SingletonComponent::class) abstract class AnalyticsModule { @Singleton @Binds abstract fun bindAnalyticsService( analyticsServiceImpl: AnalyticsServiceImpl ): AnalyticsService }
جاوا
@Module @InstallIn(SingletonComponent.class) public abstract class AnalyticsModule { @Singleton @Binds public abstract AnalyticsService bindAnalyticsService( AnalyticsServiceImpl analyticsServiceImpl ); }
برای جایگزینی اتصال AnalyticsService
در تستها، یک ماژول جدید Hilt در پوشه test
یا androidTest
با وابستگی جعلی ایجاد کنید و آن را با @TestInstallIn
حاشیهنویسی کنید. به جای آن همه تستهای موجود در آن پوشه با وابستگی جعلی تزریق میشوند.
کاتلین
@Module @TestInstallIn( components = [SingletonComponent::class], replaces = [AnalyticsModule::class] ) abstract class FakeAnalyticsModule { @Singleton @Binds abstract fun bindAnalyticsService( fakeAnalyticsService: FakeAnalyticsService ): AnalyticsService }
جاوا
@Module @TestInstallIn( components = SingletonComponent.class, replaces = AnalyticsModule.class ) public abstract class FakeAnalyticsModule { @Singleton @Binds public abstract AnalyticsService bindAnalyticsService( FakeAnalyticsService fakeAnalyticsService ); }
یک اتصال را در یک آزمایش جایگزین کنید
برای جایگزینی یک binding در یک تست به جای همه آزمایشها، یک ماژول Hilt را با استفاده از حاشیهنویسی @UninstallModules
حذف نصب کنید و یک ماژول تست جدید در داخل تست ایجاد کنید.
به دنبال مثال AnalyticsService
از نسخه قبلی، با استفاده از حاشیهنویسی @UninstallModules
در کلاس تست، به Hilt بگویید که ماژول تولید را نادیده بگیرد:
کاتلین
@UninstallModules(AnalyticsModule::class) @HiltAndroidTest class SettingsActivityTest { ... }
جاوا
@UninstallModules(AnalyticsModule.class) @HiltAndroidTest public final class SettingsActivityTest { ... }
بعد، شما باید اتصال را جایگزین کنید. یک ماژول جدید در کلاس تست ایجاد کنید که اتصال تست را تعریف می کند:
کاتلین
@UninstallModules(AnalyticsModule::class) @HiltAndroidTest class SettingsActivityTest { @Module @InstallIn(SingletonComponent::class) abstract class TestModule { @Singleton @Binds abstract fun bindAnalyticsService( fakeAnalyticsService: FakeAnalyticsService ): AnalyticsService } ... }
جاوا
@UninstallModules(AnalyticsModule.class) @HiltAndroidTest public final class SettingsActivityTest { @Module @InstallIn(SingletonComponent.class) public abstract class TestModule { @Singleton @Binds public abstract AnalyticsService bindAnalyticsService( FakeAnalyticsService fakeAnalyticsService ); } ... }
این فقط برای یک کلاس آزمایشی جایگزین اتصال می شود. اگر میخواهید پیوند را برای همه کلاسهای آزمایشی جایگزین کنید، از حاشیهنویسی @TestInstallIn
در بخش بالا استفاده کنید. از طرف دیگر، میتوانید اتصال تست را در ماژول test
برای تستهای Robolectric یا در ماژول androidTest
برای تستهای ابزاردار قرار دهید. توصیه این است که در صورت امکان از @TestInstallIn
استفاده کنید.
مقید کردن مقادیر جدید
از حاشیه نویسی @BindValue
استفاده کنید تا به راحتی فیلدهای آزمایش خود را به نمودار وابستگی Hilt متصل کنید. یک فیلد را با @BindValue
حاشیه نویسی کنید و آن را تحت نوع فیلد اعلام شده با هر واجد شرایطی که برای آن فیلد وجود دارد محدود می شود.
در مثال AnalyticsService
، می توانید AnalyticsService
با یک جعلی با استفاده از @BindValue
جایگزین کنید:
کاتلین
@UninstallModules(AnalyticsModule::class) @HiltAndroidTest class SettingsActivityTest { @BindValue @JvmField val analyticsService: AnalyticsService = FakeAnalyticsService() ... }
جاوا
@UninstallModules(AnalyticsModule.class) @HiltAndroidTest class SettingsActivityTest { @BindValue AnalyticsService analyticsService = FakeAnalyticsService(); ... }
این کار هم جایگزینی یک binding و هم ارجاع به یک binding را در آزمون شما ساده می کند و به شما امکان می دهد هر دو را همزمان انجام دهید.
@BindValue
با واجد شرایط و سایر حاشیه نویسی های آزمایشی کار می کند. به عنوان مثال، اگر از کتابخانههای آزمایشی مانند Mockito استفاده میکنید، میتوانید از آن در تست Robolectric به صورت زیر استفاده کنید:
کاتلین
... class SettingsActivityTest { ... @BindValue @ExampleQualifier @Mock lateinit var qualifiedVariable: ExampleCustomType // Robolectric tests here }
جاوا
... class SettingsActivityTest { ... @BindValue @ExampleQualifier @Mock ExampleCustomType qualifiedVariable; // Robolectric tests here }
اگر نیاز به افزودن یک multibinding دارید، می توانید از حاشیه نویسی @BindValueIntoSet
و @BindValueIntoMap
به جای @BindValue
استفاده کنید. @BindValueIntoMap
از شما میخواهد که فیلد را با حاشیهنویسی کلید نقشه نیز حاشیهنویسی کنید.
موارد خاص
Hilt همچنین ویژگی هایی را برای پشتیبانی از موارد استفاده غیر استاندارد ارائه می دهد.
نرم افزار سفارشی برای تست
اگر نمی توانید از HiltTestApplication
استفاده کنید زیرا برنامه آزمایشی شما باید برنامه دیگری را گسترش دهد، یک کلاس یا رابط جدید را با @CustomTestApplication
حاشیه نویسی کنید و مقدار کلاس پایه مورد نظر را که می خواهید برنامه Hilt تولید شده گسترش دهد، ارسال کنید.
@CustomTestApplication
یک کلاس Application
آماده برای آزمایش با Hilt ایجاد می کند که برنامه ای را که به عنوان پارامتر ارسال کرده اید گسترش می دهد.
کاتلین
@CustomTestApplication(BaseApplication::class) interface HiltTestApplication
جاوا
@CustomTestApplication(BaseApplication.class) interface HiltTestApplication { }
در مثال، Hilt یک Application
به نام HiltTestApplication_Application
تولید می کند که کلاس BaseApplication
گسترش می دهد. به طور کلی، نام برنامه تولید شده، نام کلاس حاشیه نویسی است که با _Application
ضمیمه شده است. شما باید برنامه تست هیلت تولید شده را طوری تنظیم کنید که در تست های ابزاردار یا تست های روبولکتریک همانطور که در برنامه تست توضیح داده شده است اجرا شود.
چندین شیء TestRule در آزمون ابزاری شما
اگر اشیاء TestRule
دیگری در آزمون خود دارید، راه های متعددی برای اطمینان از کارکرد همه قوانین با هم وجود دارد.
می توانید قوانین را به صورت زیر در کنار هم قرار دهید:
کاتلین
@HiltAndroidTest class SettingsActivityTest { @get:Rule var rule = RuleChain.outerRule(HiltAndroidRule(this)). around(SettingsActivityTestRule(...)) // UI tests here. }
جاوا
@HiltAndroidTest public final class SettingsActivityTest { @Rule public RuleChain rule = RuleChain.outerRule(new HiltAndroidRule(this)) .around(new SettingsActivityTestRule(...)); // UI tests here. }
از طرف دیگر، تا زمانی که HiltAndroidRule
ابتدا اجرا شود، می توانید از هر دو قانون در یک سطح استفاده کنید. ترتیب اجرا را با استفاده از صفت order
در حاشیه نویسی @Rule
مشخص کنید. این فقط در نسخه JUnit 4.13 یا بالاتر کار می کند:
کاتلین
@HiltAndroidTest class SettingsActivityTest { @get:Rule(order = 0) var hiltRule = HiltAndroidRule(this) @get:Rule(order = 1) var settingsActivityTestRule = SettingsActivityTestRule(...) // UI tests here. }
جاوا
@HiltAndroidTest public final class SettingsActivityTest { @Rule(order = 0) public HiltAndroidRule hiltRule = new HiltAndroidRule(this); @Rule(order = 1) public SettingsActivityTestRule settingsActivityTestRule = new SettingsActivityTestRule(...); // UI tests here. }
launchFragmentInContainer
استفاده از launchFragmentInContainer
از کتابخانه androidx.fragment:fragment-testing
با Hilt ممکن نیست، زیرا بر فعالیتی متکی است که با @AndroidEntryPoint
حاشیه نویسی نشده است.
به جای آن از کد launchFragmentInHiltContainer
از مخزن architecture-samples
GitHub استفاده کنید.
قبل از در دسترس بودن کامپوننت singleton از یک نقطه ورودی استفاده کنید
حاشیه نویسی @EarlyEntryPoint
یک دریچه فرار فراهم می کند زمانی که یک نقطه ورودی Hilt باید ایجاد شود قبل از اینکه جزء singleton در تست Hilt در دسترس باشد.
اطلاعات بیشتر در مورد @EarlyEntryPoint
در مستندات Hilt .