Testing with Hilt: Swapping Dependencies for Isolation

Hilt testing swaps real app components for fakes, isolating your code under test without manual setup. It's used in UI and unit tests to replace production dependencies like network clients with test doubles.
WHY IT EXISTS: Manually managing dependencies in Android tests is error-prone and boilerplate-heavy. Before Hilt, developers had to create custom test-only Dagger components or manually instantiate every class with its dependencies, making tests brittle and hard to maintain. Hilt testing automates this process for test environments.
THE MENTAL MODEL: Think of Hilt testing as a "search and replace" for your dependency graph, but only for your test environment. Your production code asks for a NetworkClient, and Hilt provides the real one. In a test, you tell Hilt, "for this test run, whenever someone asks for NetworkClient, give them this FakeNetworkClient instead." It handles creating a separate, test-specific dependency container for you.
HOW IT WORKS: Hilt uses a few key annotations. You annotate your test class with @HiltAndroidTest and use the HiltAndroidRule. This tells Hilt to generate a special test component for this test. To replace a dependency, you can use the @BindValue annotation on a field in your test class to replace any dependency of that type. For more complex scenarios, like replacing a whole module, you create a test module and use @TestInstallIn to specify which production module it replaces. Crucially, you often need to use @UninstallModules to tell Hilt to remove the production module you intend to replace, preventing conflicts.
WHEN TO USE IT: Use Hilt testing for any test that involves classes managed by Hilt. This is especially powerful for instrumentation tests (UI tests) where you need to control the entire app environment, like replacing a repository that hits a real database with one that returns canned data. It's also useful in JVM-based unit tests for ViewModels or other business logic classes that have Hilt-injected dependencies.
WHEN NOT TO USE IT: Don't use Hilt testing for simple, pure functions or classes with no Hilt-injected dependencies. If a class takes its dependencies in the constructor and you can easily instantiate it manually with mocks (e.g., using Mockito), you don't need the overhead of the Hilt test runner and component generation. The goal is isolation, and sometimes manual instantiation is simpler.
ONE CANONICAL EXAMPLE: A common UI test is verifying a screen's behavior when a network call fails. With Hilt, you would annotate your test class with @HiltAndroidTest. Then, you'd define a field like @BindValue val fakeRepository: MyRepository = FakeFailingRepository(). Hilt will inject this FakeFailingRepository everywhere the real MyRepository is used. Your test can then launch the screen and assert that the correct error message is displayed, without making a real network call.
Read the original → developer.android.com
Get five bites like this every day.
Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.