ข้อดีอย่างหนึ่งของการใช้ Dependency Injection Framework เช่น Hilt คือ จะทำให้ทดสอบโค้ดได้ง่ายขึ้น
การทดสอบ 1 หน่วย
ฮิลต์ไม่จำเป็นสำหรับการทดสอบหน่วย เพราะเมื่อทดสอบคลาสที่ใช้ Constructor Injector คุณไม่จำเป็นต้องใช้ Hilt เพื่อสร้างคลาสดังกล่าว คุณสามารถเรียกเครื่องมือสร้างชั้นเรียนได้โดยตรงโดยการส่งผ่านในรูปแบบปลอมหรือแบบจำลอง ทรัพยากร Dependency เหมือนกับที่คุณจะทำหากตัวสร้างไม่มีคำอธิบายประกอบ:
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 จะแทรกทรัพยากร Dependency อย่างที่จะแทรกในเวอร์ชันที่ใช้งานจริง โค้ด การทดสอบด้วย 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' }
Kotlin
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") }
การตั้งค่าการทดสอบ UI
คุณต้องกำกับเนื้อหาการทดสอบ UI ที่ใช้ 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
ที่รองรับภาษาฮิลต์ ไลบรารีมี 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 ตามที่อธิบายไว้ในคู่มือการทดสอบหน่วยที่มีเครื่องมือวัด ตรวจสอบว่า คุณใช้ Classpath เต็มรูปแบบ:
Groovy
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 เพื่อทดสอบเลเยอร์ UI คุณสามารถระบุแอปพลิเคชันที่จะใช้ในไฟล์ 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. } }
แทนที่การเชื่อมโยง
หากต้องการแทรกอินสแตนซ์จำลองหรือจําลองของ Dependency คุณต้องบอก 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
ที่มีทรัพยากร Dependency ปลอมและใส่คำอธิบายประกอบ
ด้วย @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
จากเวอร์ชันก่อนหน้า ให้เริ่มต้นด้วยการบอก
โปรดละเว้นโมดูลเวอร์ชันที่ใช้งานจริงโดยใช้คำอธิบายประกอบ @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
ด้วย
ปลอมโดยใช้ @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(); ... }
ซึ่งช่วยลดความซับซ้อนของทั้งการแทนที่การเชื่อมโยงและการอ้างอิงการเชื่อมโยงในการทดสอบ โดยให้คุณทำทั้ง 2 อย่างพร้อมกันได้
@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 ที่สร้างขึ้น
แอปพลิเคชันเพื่อเรียกใช้ในการทดสอบแบบมีเครื่องวัด หรือ
การทดสอบ Roolectric ตามที่อธิบายไว้ในการทดสอบ
แอปพลิเคชัน
ออบเจ็กต์ 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. }
หรือใช้ทั้ง 2 กฎในระดับเดียวกันตราบใดที่
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 ได้ เนื่องจาก Hilt อาศัยกิจกรรมที่ไม่ได้กำกับเนื้อหาด้วย @AndroidEntryPoint
ใช้เมนู
launchFragmentInHiltContainer
จาก
architecture-samples
GitHub
แทน
ใช้จุดแรกเข้าก่อนที่คอมโพเนนต์แบบ Singleton จะพร้อมใช้งาน
คำอธิบายประกอบ @EarlyEntryPoint
มีทางลับเมื่อเข้าสู่ช่อง Hilt
ต้องสร้างจุดก่อนที่คอมโพเนนต์ซิงเกิลตันจะพร้อมใช้งานใน
การทดสอบ Hilt
ข้อมูลเพิ่มเติมเกี่ยวกับ @EarlyEntryPoint
ใน
เอกสารประกอบของ Hit