Writing An Integration Test With Jetpack Compose and Dagger Hilt

Michel Onwordi
Apr 16 · 5 min read
Photo by Heri Mulyana on Unsplash

This post will show a simple setup for running an integration test between Compose and a ViewModel using Hilt.

Since Compose turned beta, I’ve been spending time getting familiar with it. I chose a side project as my learning medium — a simple app that displays a list of inventory items. Being a “responsible” engineer, I decided to add tests from the initial stages. Compose and Hilt's teams have done an excellent job documenting them, so information regarding testing is easily found. However, I didn’t find much on a scenario involving both.

Project Structure

The Repository, Viewmodel and Activity are wired together using Hilt to manage their dependencies.

Test Scenario

(Please remember this is a contrived example. An argument could be made regarding the value of such a test. However, that’s not the focus of this post)

Let’s take a closer look at some of the code in our project to understand better how to achieve this test.

The Code Under Test

Main Activity: Entry point for both Compose and Hilt. The InventoryViewModel here is provided by Hilt.
InventoryViewModel: Responsible for reading data from the repository and emitting a UiState.
Inventory List Item: A Composable responsible for displaying a list of inventory items.

(This article won’t go into details explaining how Hilt works, however, please note the annotations @AndroidEntryPoint , @HiltViewModel , @Inject are all related to the Hilt setup required to use it for dependency injection. More info here)

Looking at the code snippets above, we can observe the InventoryViewModel depends on the InventoryRepository for data. The repository would typically be responsible for fetching this data from the cloud.

When testing, we aim to create a scenario that is as close to production as possible while still being predictable and reliable. Therefore, it’s in our best interest to avoid hitting any actual servers for data. Instead, we’d prefer to provide a hard-coded list of items for test assertions.

Taking a closer look at the InventoryRepository, we see that it’s an interface. This is significant because it gives us the flexibility to provide any concrete implementation we like.

However, we would like the swap to only occur while testing. This is where Hilt and its testing capabilities come into the picture. We’ll see what those are in a few moments.

To accomplish our testing goal, we’ll require the following:

  • A predetermined list of items used for testing
  • Test dependencies for Hilt: Hilt provides API’s that allow us to manipulate the dependency injection process to suit our test needs. We can achieve this with the HiltAndroidRule, HiltTestApplication and HiltTestRunner
  • Test dependencies for Compose: This provides the ComposeTestRule which we’ll use to “load” our composable and perform assertions.
  • Patience 😂

Let’s get to it…

Adding the test dependencies

Providing the fake list of items

Hilt module to provide a fake implementation of list repository while testing

This code basically results in the creation of the module applicable only during testing. Using the @TestInstallIn annotation provided by Hilt’s test artefacts, we can specify:

  • the relevant component scope for the dependency. This is done using the components parameter,
  • the module that should be replaced by this test module using the replaces parameter.

Installing the HiltTestApplication

The same requirement applies during testing. Fortunately, Hilt provides a test application we can use and here’s how the setup looks.

We’ll use this test runner in place of the default test runner by specifying this line in our project-level Gradle file.

NOTE: Use your package name

Finally, write the test.

Ui test written using Hilt and Compose

There are a few things we should be aware of while writing the test:

  • To run an instrumentation test with Hilt, we’ll annotate the test class with @HiltAndroidTest.
  • The HiltAndroidRule allows us to perform injections within the test by calling inject(). This will enable us to replace the ViewModel’s repository dependency with the fake we defined earlier.
  • The ComposeTestRule is necessary to load the main(root) composable onto the screen. This is done by calling setContent on the test rule and passing in the composable.

Ordering the test rules

  • RuleChain API: Using this API, we could easily specify the order like this:

However, that would prevent the rules from being accessible as individual properties, thus keeping us from calling inject() and setContent{} on the Hilt and Compose test rules, respectively. Therefore, this (👇🏽) is a better approach.

  • The order parameter: JUnit 4.13 provides an even simpler way to achieve these constraints by using the order parameter of the Rule annotation. All you need to do is provide a numerical value for each rule. The provided numerical values are used to sort the rules in ascending order. Here’s what the code would look like using this approach:

Putting everything together, we’ll end up with this trivial but functional integration test.

Following the steps described above in our simplified scenario, you should be able to write an integration test for your Composed based UI’s with Hilt injected dependencies. The key takeaways are to ensure both test rules are accessible as class-level properties within the test and to use Hilt’s mechanisms for providing fake implementations while testing.

Happy Composing and Testing.

I want to thank Jossi Wolf, Hannes Struß and Lisa Onwordi for their feedback while writing this article.

Nerd For Tech

From Confusion to Clarification

Nerd For Tech

NFT is an Educational Media House. Our mission is to bring the invaluable knowledge and experiences of experts from all over the world to the novice. To know more about us, visit https://www.nerdfortech.org/. Don’t forget to check out Ask-NFT, a mentorship ecosystem we’ve started

Michel Onwordi

Written by

Android Engineer at Mercedes-benz.io

Nerd For Tech

NFT is an Educational Media House. Our mission is to bring the invaluable knowledge and experiences of experts from all over the world to the novice. To know more about us, visit https://www.nerdfortech.org/. Don’t forget to check out Ask-NFT, a mentorship ecosystem we’ve started

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store