One of the benefits of using dependency injection frameworks like Hilt is that
it makes testing your code easier.

## Unit tests

Hilt isn't necessary for unit tests, since when testing a class that uses
constructor injection, you don't need to use Hilt to instantiate that class.
Instead, you can directly call a class constructor by passing in fake or mock
dependencies, just as you would if the constructor weren't annotated:  

### Kotlin

```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

```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(...);
  }
}
```

## End-to-end tests

For integration tests, Hilt injects dependencies as it would in your production
code. Testing with Hilt requires no maintenance because Hilt automatically
generates a new set of components for each test.

### Adding testing dependencies

To use Hilt in your tests, include the `hilt-android-testing` dependency in your
project:  

### Groovy

```groovy
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

```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")
}
```
| **Note:** If you use [Jetpack
| integrations](https://developer.android.com/training/dependency-injection/hilt-jetpack), you must also include the annotation processors for the integrated libraries with `kaptTest` or `kaptAndroidTest` for Kotlin, or with `testAnnotationProcessor` or `androidTestAnnotationProcessor` for Java.

### UI test setup

You must annotate any UI test that uses Hilt with `@HiltAndroidTest`. This
annotation is responsible for generating the Hilt components for each test.

Also, you need to add the `HiltAndroidRule` to the test class. It manages the
components' state and is used to perform injection on your test:  

### Kotlin

```kotlin
@HiltAndroidTest
class SettingsActivityTest {

  @get:Rule
  var hiltRule = HiltAndroidRule(this)

  // UI tests here.
}
```

### Java

```java
@HiltAndroidTest
public final class SettingsActivityTest {

  @Rule
  public HiltAndroidRule hiltRule = new HiltAndroidRule(this);

  // UI tests here.
}
```
| **Note:** If you have other rules in your test, see [Multiple TestRule objects in
| your instrumented test](https://developer.android.com/training/dependency-injection/hilt-testing#multiple-testrules).

Next, your test needs to know about the `Application` class that Hilt
automatically generates for you.

#### Test application

You must execute instrumented tests that use Hilt in an `Application` object
that supports Hilt. The library provides `HiltTestApplication` for use in tests.
If your tests need a different base application, see [Custom application for
tests](https://developer.android.com/training/dependency-injection/hilt-testing#custom-application).

You must set your test application to run in your [instrumented
tests](https://developer.android.com/training/testing/ui-testing) or [Robolectric
tests](http://robolectric.org/). The following instructions aren't
specific to Hilt, but are general guidelines on how to specify a custom
application to run in tests.

##### Set the test application in instrumented tests

To use the Hilt test application in [instrumented
tests](https://developer.android.com/training/testing/ui-testing), you need to configure a new test runner.
This makes Hilt work for all of the instrumented tests in your project. Perform
the following steps:

1. Create a custom class that extends [`AndroidJUnitRunner`](https://developer.android.com/reference/androidx/test/runner/AndroidJUnitRunner) in the `androidTest` folder.
2. Override the `newApplication` function and pass in the name of the generated Hilt test application.

### Kotlin

```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

```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);
  }
}
```

Next, configure this test runner in your Gradle file as described in the
[instrumented unit test
guide](https://developer.android.com/training/testing/unit-testing/instrumented-unit-tests#setup). Make sure
you use the full classpath:  

### Groovy

```groovy
android {
    defaultConfig {
        // Replace com.example.android.dagger with your class path.
        testInstrumentationRunner "com.example.android.dagger.CustomTestRunner"
    }
}
```

### Kotlin

```kotlin
android {
    defaultConfig {
        // Replace com.example.android.dagger with your class path.
        testInstrumentationRunner = "com.example.android.dagger.CustomTestRunner"
    }
}
```

##### Set the test application in Robolectric tests

If you use Robolectric to test your UI layer, you can specify which application
to use in the `robolectric.properties` file:

`application = dagger.hilt.android.testing.HiltTestApplication`

Alternatively, you can configure the application on each test individually by
using Robolectric's `@Config` annotation:  

### Kotlin

```kotlin
@HiltAndroidTest
@Config(application = HiltTestApplication::class)
class SettingsActivityTest {

  @get:Rule
  var hiltRule = HiltAndroidRule(this)

  // Robolectric tests here.
}
```

### Java

```java
@HiltAndroidTest
@Config(application = HiltTestApplication.class)
class SettingsActivityTest {

  @Rule public HiltAndroidRule hiltRule = new HiltAndroidRule(this);

  // Robolectric tests here.
}
```

If you use an Android Gradle Plugin version lower than 4.2, enable
transforming `@AndroidEntryPoint` classes in local unit tests by applying the
following configuration in your module's `build.gradle` file:  

### Groovy

```groovy
hilt {
    enableTransformForLocalTests = true
}
```

### Kotlin

```kotlin
hilt {
    enableTransformForLocalTests = true
}
```

More information about `enableTransformForLocalTests` in the [Hilt
documentation](https://dagger.dev/hilt/gradle-setup#gradle-plugin-local-tests).

### Testing features

Once Hilt is ready to use in your tests, you can use several features to
customize the testing process.

#### Inject types in tests

To inject types into a test, use `@Inject` for field injection. To tell Hilt to
populate the `@Inject` fields, call `hiltRule.inject()`.

See the following example of an instrumented test:  

### Kotlin

```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

```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.
  }
}
```

#### Replace a binding

If you need to inject a fake or mock instance of a dependency, you need to tell
Hilt not to use the binding that it used in production code and to use a
different one instead. To replace a binding, you need to replace the module that
contains the binding with a test module that contains the bindings that you want
to use in the test.

For example, suppose your production code declares a binding for
`AnalyticsService` as follows:  

### Kotlin

```kotlin
@Module
@InstallIn(SingletonComponent::class)
abstract class AnalyticsModule {

  @Singleton
  @Binds
  abstract fun bindAnalyticsService(
    analyticsServiceImpl: AnalyticsServiceImpl
  ): AnalyticsService
}
```

### Java

```java
@Module
@InstallIn(SingletonComponent.class)
public abstract class AnalyticsModule {

  @Singleton
  @Binds
  public abstract AnalyticsService bindAnalyticsService(
    AnalyticsServiceImpl analyticsServiceImpl
  );
}
```

To replace the `AnalyticsService` binding in tests, create a new Hilt module in
the `test` or `androidTest` folder with the fake dependency and annotate it
with `@TestInstallIn`. All the tests in that folder are injected with the fake
dependency instead.  

### Kotlin

```kotlin
@Module
@TestInstallIn(
    components = [SingletonComponent::class],
    replaces = [AnalyticsModule::class]
)
abstract class FakeAnalyticsModule {

  @Singleton
  @Binds
  abstract fun bindAnalyticsService(
    fakeAnalyticsService: FakeAnalyticsService
  ): AnalyticsService
}
```

### Java

```java
@Module
@TestInstallIn(
    components = SingletonComponent.class,
    replaces = AnalyticsModule.class
)
public abstract class FakeAnalyticsModule {

  @Singleton
  @Binds
  public abstract AnalyticsService bindAnalyticsService(
    FakeAnalyticsService fakeAnalyticsService
  );
}
```

#### Replace a binding in a single test

To replace a binding in a single test instead of all tests, uninstall a Hilt
module from a test using the `@UninstallModules` annotation and create a new
test module inside the test.

Following the `AnalyticsService` example from the previous version, begin by telling
Hilt to ignore the production module by using the `@UninstallModules` annotation
in the test class:  

### Kotlin

```kotlin
@UninstallModules(AnalyticsModule::class)
@HiltAndroidTest
class SettingsActivityTest { ... }
```

### Java

```java
@UninstallModules(AnalyticsModule.class)
@HiltAndroidTest
public final class SettingsActivityTest { ... }
```

Next, you must replace the binding. Create a new module within the test class
that defines the test binding:  

### Kotlin

```kotlin
@UninstallModules(AnalyticsModule::class)
@HiltAndroidTest
class SettingsActivityTest {

  @Module
  @InstallIn(SingletonComponent::class)
  abstract class TestModule {

    @Singleton
    @Binds
    abstract fun bindAnalyticsService(
      fakeAnalyticsService: FakeAnalyticsService
    ): AnalyticsService
  }

  ...
}
```

### Java

```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
    );
  }
  ...
}
```

This only replaces the binding for a single test class. If you want to replace
the binding for all test classes, use the `@TestInstallIn` annotation from the
section above. Alternatively, you can put the test binding in the `test` module
for Robolectric tests, or in the `androidTest` module for instrumented tests.
The recommendation is to use `@TestInstallIn` whenever possible.
| **Warning:** You cannot uninstall modules that are not annotated with `@InstallIn`. Attempting to do so causes a compilation error.
| **Warning:** `@UninstallModules` can only uninstall `@InstallIn` modules, not `@TestInstallIn` modules. Attempting to do so causes a compilation error.
| **Note:** As Hilt creates new components for tests that use `@UninstallModules`, it can significantly impact unit test build times. Use it when necessary and prefer using `@TestInstallIn` when the bindings need to be replaced in all test classes.

#### Binding new values

Use the `@BindValue` annotation to easily bind fields in your test into the Hilt
dependency graph. Annotate a field with `@BindValue` and it will be bound under
the declared field type with any qualifiers that are present for that field.

In the `AnalyticsService` example, you can replace `AnalyticsService` with a
fake by using `@BindValue`:  

### Kotlin

```kotlin
@UninstallModules(AnalyticsModule::class)
@HiltAndroidTest
class SettingsActivityTest {

  @BindValue @JvmField
  val analyticsService: AnalyticsService = FakeAnalyticsService()

  ...
}
```

### Java

```java
@UninstallModules(AnalyticsModule.class)
@HiltAndroidTest
class SettingsActivityTest {

  @BindValue AnalyticsService analyticsService = FakeAnalyticsService();

  ...
}
```

This simplifies both replacing a binding and referencing a binding in your test
by allowing you to do both at the same time.

`@BindValue` works with qualifiers and other testing annotations. For example,
if you use testing libraries such as
[Mockito](https://site.mockito.org/), you could use it in a
Robolectric test as follows:  

### Kotlin

```kotlin
...
class SettingsActivityTest {
  ...

  @BindValue @ExampleQualifier @Mock
  lateinit var qualifiedVariable: ExampleCustomType

  // Robolectric tests here
}
```

### Java

```java
...
class SettingsActivityTest {
  ...
  @BindValue @ExampleQualifier @Mock ExampleCustomType qualifiedVariable;

  // Robolectric tests here
}
```

If you need to add a [multibinding](https://dagger.dev/dev-guide/multibindings),
you can use the `@BindValueIntoSet` and `@BindValueIntoMap` annotations in place
of `@BindValue`. `@BindValueIntoMap` requires you to also annotate the field
with a map key annotation.

## Special cases

Hilt also provides features to support nonstandard use cases.

### Custom application for tests

If you cannot use `HiltTestApplication` because your test application needs to
extend another application, annotate a new class or interface with
`@CustomTestApplication`, passing in the value of the base class you want the
generated Hilt application to extend.

`@CustomTestApplication` will generate an `Application` class ready for testing
with Hilt that extends the application you passed as a parameter.  

### Kotlin

```kotlin
@CustomTestApplication(BaseApplication::class)
interface HiltTestApplication
```

### Java

```java
@CustomTestApplication(BaseApplication.class)
interface HiltTestApplication { }
```

In the example, Hilt generates an `Application` named
`HiltTestApplication_Application` that extends the `BaseApplication` class. In
general, the name of the generated application is the name of the annotated
class appended with `_Application`. You must set the generated Hilt test
application to run in your [instrumented tests](https://developer.android.com/training/testing/ui-testing) or
[Robolectric tests](http://robolectric.org/) as described in [Test
application](https://developer.android.com/training/dependency-injection/hilt-testing#test-application).
| **Note:** Because `HiltTestApplication_Application` is code that Hilt generates at runtime, the IDE might highlight it in red until you run your tests.

### Multiple TestRule objects in your instrumented test

If you have other `TestRule` objects in your test, there are multiple ways to
ensure that all of the rules work together.

You can wrap the rules together as follows:  

### Kotlin

```kotlin
@HiltAndroidTest
class SettingsActivityTest {

  @get:Rule
  var rule = RuleChain.outerRule(HiltAndroidRule(this)).
        around(SettingsActivityTestRule(...))

  // UI tests here.
}
```

### Java

```java
@HiltAndroidTest
public final class SettingsActivityTest {

  @Rule public RuleChain rule = RuleChain.outerRule(new HiltAndroidRule(this))
        .around(new SettingsActivityTestRule(...));

  // UI tests here.
}
```

Alternatively, you can use both rules at the same level as long as the
`HiltAndroidRule` executes first. Specify the execution order using the
`order` attribute in the `@Rule` annotation. This only works in JUnit version
4.13 or higher:  

### Kotlin

```kotlin
@HiltAndroidTest
class SettingsActivityTest {

  @get:Rule(order = 0)
  var hiltRule = HiltAndroidRule(this)

  @get:Rule(order = 1)
  var settingsActivityTestRule = SettingsActivityTestRule(...)

  // UI tests here.
}
```

### Java

```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

It is not possible to use `launchFragmentInContainer` from the
`androidx.fragment:fragment-testing` library with Hilt, because it relies on an
activity that is not annotated with `@AndroidEntryPoint`.

Use the
[`launchFragmentInHiltContainer`](https://github.com/android/architecture-samples/blob/views-hilt/app/src/androidTest/java/com/example/android/architecture/blueprints/todoapp/HiltExt.kt#L37)
code from the
[`architecture-samples`](https://github.com/android/architecture-samples) GitHub
repository instead.

### Use an entry point before the singleton component is available

The `@EarlyEntryPoint` annotation provides an escape hatch when a Hilt entry
point needs to be created before the singleton component is available in a
Hilt test.

More information about `@EarlyEntryPoint` in the
[Hilt documentation](https://dagger.dev/hilt/early-entry-point).