מושגים והטמעה של Jetpack Compose
אחד מהיתרונות של שימוש ב-frameworks של החדרת תלות כמו Hilt הוא שהם מקלים על בדיקת הקוד.
בדיקות יחידה (unit testing)
לא צריך את Hilt לבדיקות יחידה, כי כשבודקים מחלקה שמשתמשת בהחדרה ל-constructor, לא צריך להשתמש ב-Hilt כדי ליצור מופע של המחלקה הזו. במקום זאת, אתם יכולים לקרוא ישירות ל-constructor של הכיתה על ידי העברת יחסי תלות מזויפים או מדומים, בדיוק כמו שהייתם עושים אם ה-constructor לא היה מסומן:
Kotlin
@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(...) } }
Java
@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.57.1' // ...with Kotlin. kaptTest 'com.google.dagger:hilt-android-compiler:2.57.1' // ...with Java. testAnnotationProcessor 'com.google.dagger:hilt-android-compiler:2.57.1' // For instrumented tests. androidTestImplementation 'com.google.dagger:hilt-android-testing:2.57.1' // ...with Kotlin. kaptAndroidTest 'com.google.dagger:hilt-android-compiler:2.57.1' // ...with Java. androidTestAnnotationProcessor 'com.google.dagger:hilt-android-compiler:2.57.1' }
Kotlin
dependencies { // For Robolectric tests. testImplementation("com.google.dagger:hilt-android-testing:2.57.1") // ...with Kotlin. kaptTest("com.google.dagger:hilt-android-compiler:2.57.1") // ...with Java. testAnnotationProcessor("com.google.dagger:hilt-android-compiler:2.57.1") // For instrumented tests. androidTestImplementation("com.google.dagger:hilt-android-testing:2.57.1") // ...with Kotlin. kaptAndroidTest("com.google.dagger:hilt-android-compiler:2.57.1") // ...with Java. androidTestAnnotationProcessor("com.google.dagger:hilt-android-compiler:2.57.1") }
הגדרת בדיקת ממשק משתמש
צריך להוסיף הערה לכל בדיקת ממשק משתמש שמשתמשת ב-Hilt עם @HiltAndroidTest. ההערה הזו אחראית ליצירת רכיבי Hilt לכל בדיקה.
בנוסף, צריך להוסיף את HiltAndroidRule למחלקת הבדיקה. הוא מנהל את המצב של הרכיבים ומשמש להזרקה בבדיקה:
Kotlin
@HiltAndroidTest class SettingsActivityTest { @get:Rule var hiltRule = HiltAndroidRule(this) // UI tests here. }
Java
@HiltAndroidTest public final class SettingsActivityTest { @Rule public HiltAndroidRule hiltRule = new HiltAndroidRule(this); // UI tests here. }
בשלב הבא, הבדיקה צריכה לדעת על המחלקה Application ש-Hilt יוצר באופן אוטומטי.
אפליקציית בדיקה
צריך להריץ בדיקות אינסטרומנטציה שמשתמשות ב-Hilt באובייקט Application שתומך ב-Hilt. הספרייה מספקת את HiltTestApplication לשימוש בבדיקות.
אם לבדיקות שלכם נדרשת אפליקציית בסיס אחרת, עיינו בקטע אפליקציה בהתאמה אישית לבדיקות.
אתם צריכים להגדיר את אפליקציית הבדיקה כך שתפעל בבדיקות עם כלים או בבדיקות Robolectric. ההוראות הבאות לא ספציפיות ל-Hilt, אלא הנחיות כלליות איך לציין אפליקציה בהתאמה אישית להפעלה בבדיקות.
הגדרת אפליקציית הבדיקה בבדיקות אינסטרומנטציה
כדי להשתמש באפליקציית הבדיקה של Hilt בבדיקות עם כלים, צריך להגדיר כלי חדש להרצת בדיקות. כך Hilt יפעל בכל בדיקות האינסטרומנטציה בפרויקט. כך עושים את זה:
- יוצרים מחלקה בהתאמה אישית שמרחיבה את
AndroidJUnitRunnerבתיקייהandroidTest. - מבטלים את הפונקציה
newApplicationומעבירים את השם של אפליקציית הבדיקה שנוצרה ב-Hilt.
Kotlin
// 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) } }
Java
// 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, כמו שמתואר במדריך לבדיקת יחידה עם אינסטרומנטציה. חשוב לוודא שאתם משתמשים בנתיב המלא של המחלקה:
מגניב
android { defaultConfig { // Replace com.example.android.dagger with your class path. testInstrumentationRunner "com.example.android.dagger.CustomTestRunner" } }
Kotlin
android { defaultConfig { // Replace com.example.android.dagger with your class path. testInstrumentationRunner = "com.example.android.dagger.CustomTestRunner" } }
הגדרת אפליקציית הבדיקה בבדיקות Robolectric
אם אתם משתמשים ב-Robolectric כדי לבדוק את שכבת ממשק המשתמש, אתם יכולים לציין באיזו אפליקציה להשתמש בקובץ robolectric.properties:
application = dagger.hilt.android.testing.HiltTestApplication
לחלופין, אפשר להגדיר את האפליקציה בכל בדיקה בנפרד באמצעות ההערה @Config של Robolectric:
Kotlin
@HiltAndroidTest @Config(application = HiltTestApplication::class) class SettingsActivityTest { @get:Rule var hiltRule = HiltAndroidRule(this) // Robolectric tests here. }
Java
@HiltAndroidTest @Config(application = HiltTestApplication.class) class SettingsActivityTest { @Rule public HiltAndroidRule hiltRule = new HiltAndroidRule(this); // Robolectric tests here. }
אם אתם משתמשים בפלאגין של Android Gradle בגרסה ישנה יותר מ-4.2, אתם צריכים להפעיל את האפשרות להמיר מחלקות של @AndroidEntryPoint בבדיקות יחידה מקומיות. כדי לעשות את זה, צריך להוסיף את ההגדרה הבאה לקובץ build.gradle של המודול:
מגניב
hilt { enableTransformForLocalTests = true }
Kotlin
hilt { enableTransformForLocalTests = true }
מידע נוסף על enableTransformForLocalTests זמין במסמכי התיעוד של Hilt.
תכונות בבדיקה
אחרי ש-Hilt מוכן לשימוש בבדיקות, אתם יכולים להשתמש בכמה תכונות כדי להתאים אישית את תהליך הבדיקה.
הזרקת סוגים בבדיקות
כדי להחדיר סוגים לבדיקה, משתמשים ב-@Inject להחדרה לשדה. כדי להורות ל-Hilt לאכלס את השדות של @Inject, צריך להפעיל את hiltRule.inject().
דוגמה לבדיקת אינסטרומנטציה:
Kotlin
@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. } }
Java
@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 באופן הבא:
Kotlin
@Module @InstallIn(SingletonComponent::class) abstract class AnalyticsModule { @Singleton @Binds abstract fun bindAnalyticsService( analyticsServiceImpl: AnalyticsServiceImpl ): AnalyticsService }
Java
@Module @InstallIn(SingletonComponent.class) public abstract class AnalyticsModule { @Singleton @Binds public abstract AnalyticsService bindAnalyticsService( AnalyticsServiceImpl analyticsServiceImpl ); }
כדי להחליף את הקישור של AnalyticsService בבדיקות, יוצרים מודול Hilt חדש בתיקייה test או androidTest עם התלות המזויפת ומוסיפים לה הערה עם @TestInstallIn. במקום זאת, כל הבדיקות בתיקייה הזו מוזרקות עם התלות המזויפת.
Kotlin
@Module @TestInstallIn( components = [SingletonComponent::class], replaces = [AnalyticsModule::class] ) abstract class FakeAnalyticsModule { @Singleton @Binds abstract fun bindAnalyticsService( fakeAnalyticsService: FakeAnalyticsService ): AnalyticsService }
Java
@Module @TestInstallIn( components = SingletonComponent.class, replaces = AnalyticsModule.class ) public abstract class FakeAnalyticsModule { @Singleton @Binds public abstract AnalyticsService bindAnalyticsService( FakeAnalyticsService fakeAnalyticsService ); }
החלפת קישור בבדיקה אחת
כדי להחליף קישור בבדיקה אחת במקום בכל הבדיקות, מסירים מודול Hilt מבדיקה באמצעות ההערה @UninstallModules ויוצרים מודול בדיקה חדש בתוך הבדיקה.
בהמשך לדוגמה של AnalyticsService מהגרסה הקודמת, קודם כל צריך להורות ל-Hilt להתעלם מהמודול של סביבת הייצור באמצעות ההערה @UninstallModules במחלקת הבדיקה:
Kotlin
@UninstallModules(AnalyticsModule::class) @HiltAndroidTest class SettingsActivityTest { ... }
Java
@UninstallModules(AnalyticsModule.class) @HiltAndroidTest public final class SettingsActivityTest { ... }
בשלב הבא, צריך להחליף את הקישור. יוצרים מודול חדש בתוך מחלקת הבדיקה שמגדיר את הקישור לבדיקה:
Kotlin
@UninstallModules(AnalyticsModule::class) @HiltAndroidTest class SettingsActivityTest { @Module @InstallIn(SingletonComponent::class) abstract class TestModule { @Singleton @Binds abstract fun bindAnalyticsService( fakeAnalyticsService: FakeAnalyticsService ): AnalyticsService } ... }
Java
@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 ב-fake באמצעות @BindValue:
Kotlin
@UninstallModules(AnalyticsModule::class) @HiltAndroidTest class SettingsActivityTest { @BindValue @JvmField val analyticsService: AnalyticsService = FakeAnalyticsService() ... }
Java
@UninstallModules(AnalyticsModule.class) @HiltAndroidTest class SettingsActivityTest { @BindValue AnalyticsService analyticsService = FakeAnalyticsService(); ... }
כך קל יותר להחליף קישור ולהפנות לקישור בבדיקה, כי אפשר לעשות את שתי הפעולות בו-זמנית.
@BindValue פועל עם מגדירים והערות בדיקה אחרות. לדוגמה, אם אתם משתמשים בספריות בדיקה כמו Mockito, אתם יכולים להשתמש בהן בבדיקת Robolectric באופן הבא:
Kotlin
... class SettingsActivityTest { ... @BindValue @ExampleQualifier @Mock lateinit var qualifiedVariable: ExampleCustomType // Robolectric tests here }
Java
... class SettingsActivityTest { ... @BindValue @ExampleQualifier @Mock ExampleCustomType qualifiedVariable; // Robolectric tests here }
אם אתם צריכים להוסיף multibinding, אתם יכולים להשתמש באנוטציות @BindValueIntoSet ו-@BindValueIntoMap במקום @BindValue. כדי להשתמש ב-@BindValueIntoMap, צריך להוסיף לשדה גם הערה עם מפתח מפה.
מקרים מיוחדים
Hilt מספקת גם תכונות שתומכות בתרחישי שימוש לא סטנדרטיים.
אפליקציה מותאמת אישית לבדיקות
אם אתם לא יכולים להשתמש ב-HiltTestApplication כי אפליקציית הבדיקה צריכה להרחיב אפליקציה אחרת, הוסיפו הערה לממשק או למחלקה חדשה באמצעות @CustomTestApplication, והעבירו את הערך של המחלקה הבסיסית שאתם רוצים שאפליקציית Hilt שנוצרה תרחיב.
@CustomTestApplication ייצור מחלקת Application שמוכנה לבדיקה עם Hilt, שמרחיבה את האפליקציה שהעברתם כפרמטר.
Kotlin
@CustomTestApplication(BaseApplication::class) interface HiltTestApplication
Java
@CustomTestApplication(BaseApplication.class) interface HiltTestApplication { }
בדוגמה, Hilt יוצר Application בשם HiltTestApplication_Application שמרחיב את המחלקה BaseApplication. באופן כללי, השם של האפליקציה שנוצרה הוא השם של המחלקה עם ההערות, בתוספת _Application. אתם צריכים להגדיר את אפליקציית הבדיקה של Hilt שנוצרה כך שתפעל בבדיקות אינסטרומנטציה או בבדיקות Robolectric, כפי שמתואר בקטע אפליקציית בדיקה.
מספר אובייקטים של TestRule בבדיקת אינסטרומנטציה
אם יש לכם אובייקטים אחרים של TestRule בבדיקה, יש כמה דרכים לוודא שכל הכללים פועלים ביחד.
אפשר לאחד את הכללים באופן הבא:
Kotlin
@HiltAndroidTest class SettingsActivityTest { @get:Rule var rule = RuleChain.outerRule(HiltAndroidRule(this)). around(SettingsActivityTestRule(...)) // UI tests here. }
Java
@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 ואילך:
Kotlin
@HiltAndroidTest class SettingsActivityTest { @get:Rule(order = 0) var hiltRule = HiltAndroidRule(this) @get:Rule(order = 1) var settingsActivityTestRule = SettingsActivityTestRule(...) // UI tests here. }
Java
@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.