---
title: "Dagger Hilt: Testing injected Android components with code coverage"
source: "/writing/dagger-hilt-testing-injected-android-components-with-code-coverage/"
---

Article

# Dagger Hilt: Testing injected Android components with code coverage

Alex Vanyo

November 17, 2020

_Dagger Hilt, JaCoCo, Robolectric, Espresso, oh my!_

[Dagger Hilt](https://dagger.dev/hilt/) is Google's new opinionated add-on for setting up Dagger 2 for Android. Through its tie-ins with `androidx` and preconfigured components, it should be able to meet the common dependency injection demands of most apps.

Google also lays out [a testing philosophy](https://dagger.dev/hilt/testing-philosophy) that Hilt can help realize, using the real Dagger graph in tests. The goal of this article is to make that philosophy a reality, by providing all of the build script pieces and an inheritance trick needed to set up testing an Android project with code coverage using Hilt, Robolectric, Espresso and JaCoCo.

-   [1: Configure JaCoCo](#id-0)
-   [2: Setup Robolectric and Espresso](#id-1)
-   [3a: Configure Hilt with the Gradle plugin](#id-2)
-   [3b: Configure Hilt without the Gradle plugin](#id-3)

This article won't explain how to write tests for Robolectric and Espresso, or how to use Hilt's testing utilities, so refer to the documentation for those projects for examples.

### Step 1: Configure JaCoCo

The necessary JaCoCo configuration looks basically the same as a normal Android JaCoCo setup. Since it's not a trivial task to set up, here is a sample build configuration that creates separate test reports for each application variant while also allowing for exclusions:

### Step 2: Setup Robolectric and Espresso

The next step is setting up [Robolectric](http://robolectric.org/) and Espresso. Together, these allow running UI-like tests in the JVM without needing an emulator.

### Step 3a: Configure Hilt with the Gradle plugin

There are two options for setting up Hilt, with or without the accompanied Gradle Plugin. For completeness, this is the normal setup required for Hilt at runtime, without tests. In the project's root `build.gradle.kts`, we'll add the Gradle plugin:

And in the `app/build.gradle.kts`, we will apply the plugin and add the runtime dependencies:

Because the Hilt Gradle plugin performs a bytecode transformation, running Robolectric tests now will cause JaCoCo to complain that the execution data for any transformed class annotated with `@AndroidEntryPoint` doesn't match. To get around this, we can "lift" the transformation to a subclass that contains no functional code that we care about, which allows the actual implementation to remain untouched and trackable by JaCoCo:

Another note: Currently, the `hilt.enableTransformForLocalTests` only works with Gradle, and does not work if running the tests through Android Studio directly (tracked by [https://github.com/google/dagger/pull/1811](https://github.com/google/dagger/pull/1811) and [https://issuetracker.google.com/37003772](https://issuetracker.google.com/37003772) . To workaround this, we can avoid using the Grade Plugin entirely (see below).

### Step 3b: Configure Hilt without the Gradle plugin

In lieu of using the Hilt Gradle plugin, the desired superclass for an entry point can be passed to the `@AndroidEntryPoint`, and then the entry point directly extends from the generated `Hilt_*` class. Using the generated code directly means the root `build.gradle.kts` can remain untouched, and the `app/build.gradle.kts` doesn't apply the plugin:

Although we don't need to workaround the bytecode transformation for JaCoCo when the Hilt Gradle plugin isn't applied, there is still an issue with having to pass the superclass to `@AndroidEntryPoint`. If the superclass has generic type arguments, those can't be specified in the annotation. The workaround for this is a similar "lift" for the transformation, to ensure that the direct superclass has no type arguments:

And that's it! With Hilt, Robolectric, Espresso, and JaCoCo, we can test actual Android objects that are injected with Dagger with code coverage. This allows for an incredibly useful set of tests between pure unit tests and full UI tests, that ensure that an application's actual Dagger graph and all of its resolved dependencies are performing as expected. Using tools like `@UninstallModules`, modules for the edges of an application (such as networking) can be replaced, allowing for fast, non-flaky tests that exercise a lot of code that may previously have gone untested.

_Alex works at_ [_Livefront_](https://livefront.com/) _, where we like to test everything we possibly can._

### Current Caveats:

There are a few shortcomings and limitations currently that might be fixed in the future. In no particular order, here are a few:

-   Robolectric tests currently can't be written JUnit 5 directly, blocked by [https://github.com/robolectric/robolectric/issues/3477](https://github.com/robolectric/robolectric/issues/3477) . Robolectric tests can be run with JUnit 5 Vintage Engine, so pure Kotlin tests can use JUnit 5 while Robolectric tests are still using JUnit 4.
-   As mentioned above, the `hilt.enableTransformForLocalTests` only works when running tests through Gradle, and does not work if running the tests through Android Studio directly: [https://github.com/google/dagger/issues/1956](https://github.com/google/dagger/issues/1956) and [https://issuetracker.google.com/issues/37076369](https://issuetracker.google.com/issues/37076369) .
-   Hilt does not currently work with `FragmentScenario` directly, since the fragment under test must be contained in a Hilt activity. As a workaround, a simple `@AndroidEntryPoint TestActivity : AppCompatActivity()` can be defined (also added to the `debug/AndroidManifest.xml`) xml for use in tests. Also see [https://developer.android.com/training/dependency-injection/hilt-testing#launchfragment](https://developer.android.com/training/dependency-injection/hilt-testing#launchfragment) for an equivalent `[launchFragmentInHiltContainer](https://github.com/android/architecture-samples/blob/dev-hilt/app/src/androidTest/java/com/example/android/architecture/blueprints/todoapp/HiltExt.kt#L38)` definition.

-   Alex Vanyo

    Software Engineer

    Alex Vanyo

### Tags

[Digital Engineering](/insights/all/?topic=digital-engineering) [Mobile Apps](/insights/all/?topic=mobile-apps)

### Share

-   Copied

## View these next.

[See all](/insights/all/?type=writing)

-   [

    Article

    How To Sabotage Your Project Using Inconsistency

    Collin Flynn

    ](/writing/how-to-sabotage-your-project-using-inconsistency/)
-   [

    Article

    Unit Testing race conditions by creating chaos (Swift)

    Sean Berry

    ](/writing/unit-testing-race-conditions-by-creating-chaos-swift/)
-   [

    Article

    UIApplicationDelegate call sequence reference

    Sean Berry

    ](/writing/uiapplicationdelegate-call-sequence-reference/)
