Một trong những lợi ích của việc sử dụng các khung chèn phần phụ thuộc như Hilt là giúp bạn kiểm thử mã dễ dàng hơn.
Kiểm thử đơn vị
Bạn không cần dùng Hilt để kiểm thử đơn vị vì khi kiểm thử một lớp sử dụng tính năng chèn hàm khởi tạo, bạn không cần phải sử dụng Hilt để tạo bản sao của lớp đó. Thay vào đó, bạn có thể trực tiếp gọi một hàm khởi tạo lớp bằng cách truyền vào các phần phụ thuộc giả hoặc mô phỏng, giống như cách bạn sẽ làm nếu hàm khởi tạo không được chú thích:
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(...); } }
Kiểm thử toàn diện
Đối với thử nghiệm tích hợp, Hilt sẽ chèn các phần phụ thuộc giống như trong mã sản xuất. Việc sử dụng Hilt để kiểm thử không yêu cầu bảo trì vì Hilt tự động tạo một tập hợp các thành phần mới cho mỗi kiểm thử.
Thêm các phần phụ thuộc kiểm thử
Để sử dụng Hilt trong các kiểm thử, hãy đưa phần phụ thuộc hilt-android-testing
vào dự án:
Groovy
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") }
Thiết lập thử nghiệm giao diện người dùng
Bạn phải chú thích mọi kiểm thử giao diện người dùng sử dụng Hilt với @HiltAndroidTest
. Chú thích này chịu trách nhiệm tạo các thành phần Hilt cho mỗi lần kiểm thử.
Ngoài ra, bạn cần thêm HiltAndroidRule
vào lớp kiểm thử. Công cụ này quản lý trạng thái của các thành phần và được dùng để thực hiện thao tác chèn trong kiểm thử:
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. }
Tiếp theo, kiểm thử cần được biết về lớp Application
mà Hilt tự động tạo cho bạn.
Kiểm thử ứng dụng
Bạn phải thực thi các kiểm thử đo lường sử dụng Hilt trong đối tượng Application
để hỗ trợ Hilt. Thư viện này cung cấp HiltTestApplication
để sử dụng trong kiểm thử.
Nếu chương trình kiểm thử của bạn cần một ứng dụng cơ sở khác, vui lòng xem Tùy chỉnh ứng dụng để kiểm thử.
Bạn phải thiết lập ứng dụng kiểm thử để chạy trong các kiểm thử đo lường hoặc kiểm thử Robolectric. Các hướng dẫn sau đây không dành riêng cho Hilt, nhưng là hướng dẫn chung về cách chỉ định một ứng dụng tuỳ chỉnh để chạy trong các lần kiểm thử.
Đặt ứng dụng kiểm thử trong các kiểm thử đo lường
Để sử dụng ứng dụng kiểm thử Hilt trong kiểm thử đo lường, bạn cần định cấu hình một trình chạy kiểm thử mới. Điều này giúp Hilt hoạt động cho tất cả các kiểm thử đo lường trong dự án của bạn. Thực hiện các bước sau đây:
- Tạo một lớp tuỳ chỉnh giúp mở rộng
AndroidJUnitRunner
trong thư mụcandroidTest
. - Ghi đè hàm
newApplication
và truyền tên của ứng dụng kiểm thử Hilt được tạo.
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); } }
Tiếp theo, hãy định cấu hình trình chạy kiểm thử này trong tệp Gradle như được mô tả ở phần hướng dẫn kiểm thử đơn vị đo lường. Hãy đảm bảo là bạn sử dụng đường dẫn lớp đầy đủ:
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" } }
Đặt ứng dụng kiểm thử trong các kiểm thử Robolectric
Nếu sử dụng Robolectric để kiểm thử lớp giao diện người dùng, bạn có thể chỉ định ứng dụng nào sẽ sử dụng trong tệp robolectric.properties
:
application = dagger.hilt.android.testing.HiltTestApplication
Ngoài ra, bạn có thể định cấu hình ứng dụng cho từng lần kiểm thử riêng lẻ bằng cách sử dụng chú thích @Config
của 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. }
Nếu bạn sử dụng phiên bản Trình bổ trợ Android cho Gradle thấp hơn phiên bản 4.2, hãy bật tính năng chuyển đổi các lớp @AndroidEntryPoint
trong kiểm thử đơn vị cục bộ bằng cách áp dụng cấu hình sau trong tệp build.gradle
của mô-đun:
Groovy
hilt { enableTransformForLocalTests = true }
Kotlin
hilt { enableTransformForLocalTests = true }
Thông tin thêm về enableTransformForLocalTests
trong tài liệu về Hilt.
Các tính năng thử nghiệm
Khi Hilt đã sẵn sàng để sử dụng trong quá trình kiểm thử, bạn có thể dùng một số tính năng để tuỳ chỉnh quy trình kiểm thử.
Chèn các loại trong kiểm thử
Để chèn các loại vào một thử nghiệm, hãy sử dụng @Inject
để chèn trường. Để yêu cầu Hilt điền vào các trường @Inject
, hãy gọi hiltRule.inject()
.
Hãy xem ví dụ sau về kiểm thử đo lường:
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. } }
Thay thế một liên kết
Nếu cần chèn một bản sao giả mạo hoặc mô phỏng của một phần phụ thuộc, bạn cần yêu cầu Hilt không sử dụng liên kết mà nó đã sử dụng trong mã phát hành chính thức, đồng thời sử dụng một liên kết khác. Để thay thế một liên kết, bạn cần thay thế mô-đun chứa liên kết bằng một mô-đun kiểm thử có chứa các liên kết mà bạn muốn sử dụng trong quá trình kiểm thử.
Ví dụ, giả sử mã phát hành chính thức khai báo một liên kết cho AnalyticsService
như sau:
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 ); }
Để thay thế liên kết AnalyticsService
trong các kiểm thử, hãy tạo một mô-đun Hilt mới trong thư mục test
hoặc androidTest
bằng phần phụ thuộc giả mạo rồi chú thích
bằng @TestInstallIn
. Thay vào đó, tất cả kiểm thử trong thư mục đó sẽ được chèn phần phụ thuộc giả mạo.
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 ); }
Thay thế liên kết trong một kiểm thử duy nhất
Để thay thế một liên kết trong một kiểm thử đơn thay vì mọi kiểm thử, hãy gỡ cài đặt mô-đun Hilt của một kiểm thử bằng cách sử dụng chú thích @UninstallModules
, đồng thời tạo một mô-đun kiểm thử mới bên trong kiểm thử đó.
Theo ví dụ về AnalyticsService
từ phiên bản trước, hãy bắt đầu bằng cách yêu cầu Hilt bỏ qua mô-đun phát hành chính thức bằng cách sử dụng chú thích @UninstallModules
trong lớp kiểm thử:
Kotlin
@UninstallModules(AnalyticsModule::class) @HiltAndroidTest class SettingsActivityTest { ... }
Java
@UninstallModules(AnalyticsModule.class) @HiltAndroidTest public final class SettingsActivityTest { ... }
Tiếp theo, bạn phải thay thế liên kết. Tạo một mô-đun mới trong lớp kiểm thử xác định liên kết kiểm thử:
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 ); } ... }
Thao tác này chỉ thay thế liên kết cho một lớp kiểm thử duy nhất. Nếu bạn muốn thay thế liên kết cho tất cả các lớp kiểm thử, hãy sử dụng chú thích @TestInstallIn
của phần trên. Ngoài ra, bạn có thể đặt liên kết kiểm thử trong mô-đun test
dành cho kiểm thử Robolectric, hoặc trong mô-đun androidTest
đối với kiểm thử đo lường.
Bạn nên sử dụng @TestInstallIn
bất cứ khi nào có thể.
Liên kết các giá trị mới
Sử dụng chú thích @BindValue
để dễ dàng liên kết các trường trong kiểm thử vào biểu đồ phần phụ thuộc Hilt. Chú thích một trường bằng @BindValue
và trường này sẽ được liên kết với loại trường đã khai báo bằng bất kỳ bộ hạn định nào có trong trường đó.
Trong ví dụ AnalyticsService
, bạn có thể thay thế AnalyticsService
bằng một nội dung giả bằng cách sử dụng @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(); ... }
Việc này giúp đơn giản hoá cả việc thay thế lẫn tham chiếu một liên kết trong quá trình kiểm thử bằng cách cho phép bạn thực hiện cả hai cùng lúc.
@BindValue
hoạt động với bộ hạn định và các chú thích kiểm thử khác. Chẳng hạn nếu sử dụng các thư viện kiểm thử như Mockito, bạn có thể sử dụng các thư viện đó trong kiểm thử Robolectric như sau:
Kotlin
... class SettingsActivityTest { ... @BindValue @ExampleQualifier @Mock lateinit var qualifiedVariable: ExampleCustomType // Robolectric tests here }
Java
... class SettingsActivityTest { ... @BindValue @ExampleQualifier @Mock ExampleCustomType qualifiedVariable; // Robolectric tests here }
Nếu cần thêm nhiều liên kết, bạn có thể sử dụng chú thích @BindValueIntoSet
và @BindValueIntoMap
thay cho @BindValue
. @BindValueIntoMap
cũng yêu cầu bạn chú thích trường bằng chú thích khóa bản đồ.
Các trường hợp đặc biệt
Hilt cũng cung cấp các tính năng để hỗ trợ các trường hợp sử dụng không theo chuẩn.
Tùy chỉnh ứng dụng để thử nghiệm
Nếu bạn không thể dùng HiltTestApplication
vì ứng dụng kiểm thử cần mở rộng một ứng dụng khác, hãy chú thích một lớp hoặc giao diện mới bằng @CustomTestApplication
, truyền giá trị của lớp cơ sở mà bạn muốn ứng dụng Hilt đã tạo sẽ mở rộng.
@CustomTestApplication
sẽ tạo một lớp Application
sẵn sàng để thử nghiệm với Hilt, lớp này sẽ mở rộng ứng dụng mà bạn đã truyền dưới dạng tham số.
Kotlin
@CustomTestApplication(BaseApplication::class) interface HiltTestApplication
Java
@CustomTestApplication(BaseApplication.class) interface HiltTestApplication { }
Trong ví dụ này, Hilt sẽ tạo một Application
có tên là HiltTestApplication_Application
mở rộng lớp BaseApplication
. Nói chung, tên của ứng dụng đã tạo là tên của lớp chú thích được thêm vào _Application
. Bạn phải thiết lập ứng dụng kiểm thử Hilt đã tạo để chạy trongkiểm thử đo lường hoặc
Kiểm thử Robolectric như được mô tả trong phần Kiểm thử ứng dụng.
Nhiều đối tượng TestRule trong kiểm thử đo lường
Nếu bạn có các đối tượng TestRule
khác trong kiểm thử, có nhiều cách để đảm bảo tất cả quy tắc đều hoạt động cùng nhau.
Bạn có thể gói các quy tắc lại với nhau như sau:
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. }
Ngoài ra, bạn có thể sử dụng cả hai quy tắc ở cùng một cấp, miễn là HiltAndroidRule
được thực thi trước. Hãy chỉ định thứ tự thực thi bằng cách sử dụng thuộc tính order
trong chú thích @Rule
. Thuộc tính này chỉ hoạt động trong JUnit phiên bản 4.13 trở lên:
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
Bạn không thể sử dụng launchFragmentInContainer
trong thư viện androidx.fragment:fragment-testing
bằng Hilt, vì thư viện này dựa vào hoạt động không được chú thích bằng @AndroidEntryPoint
.
Thay vào đó, hãy sử dụng mã launchFragmentInHiltContainer
trong kho lưu trữ GitHub của architecture-samples
.
Sử dụng một điểm truy cập trước khi có thể dùng thành phần singleton
Chú thích @EarlyEntryPoint
cung cấp một giải pháp khi cần tạo một điểm truy cập Hilt trước khi thành phần singleton có trong kiểm thử Hilt.
Vui lòng tìm hiểu thêm thông tin về @EarlyEntryPoint
trong tài liệu về Hilt.