google / dagger

A fast dependency injector for Android and Java.
https://dagger.dev
Apache License 2.0
17.42k stars 2.01k forks source link

Disable Hilt for tests #3206

Closed EliottLujan closed 2 years ago

EliottLujan commented 2 years ago

Hi! First of all thanks for the great work on Hilt, this is really helpful to us!

When doing UI tests, we usually mock our ViewModels to send some mocked data to the UI. We then check if the displayed UI is what's expected. This is a very different philosophy than what Hilt recommends because we do not care what the ViewModel dependencies are and therefore, we dont actually need Hilt for this kind of tests.

Having Hilt for tests forces us to create a test dagger Module for our repositories, which the ViewModel depends on. Also, this means an instrumented test with Hilt creates a real instance of the ViewModel and its dependencies.

An option that would help us a lot would be to disable Hilt for tests (mainly disable code generation and code manipulation). What do you think ? Would it make sense to have this kind of option baked into Hilt ?

We tried to manually disable the Gradle tasks that run code transformation (all the kapt's tasks as well as the transformWithAsm tasks). But it didn't seem to work, as the Hilt plugin is still applied and the UI tests fails because some requirements are not met, for instance Hilt Fragments must be attached to an @AndroidEntryPoint Activity

If there are other options to disable Hilt for tests, feel free to let me know 😄

Again, thanks for you work!

bcorso commented 2 years ago

This is a very different philosophy than what Hilt recommends because we do not care what the ViewModel dependencies are and therefore, we dont actually need Hilt for this kind of tests.

Note that Hilt's testing philosophy is not just that Hilt makes it possible to test using real dependencies, but that in many/(most) cases its better to use the real dependencies. Since Hilt was built with this philosophy in mind, it's often easier to use the real dependencies than mock/fake dependencies in tests.

That said, we do have options if you want to disable Hilt in tests (see below).

An option that would help us a lot would be to disable Hilt for tests (mainly disable code generation and code manipulation).

To disable Hilt injection in your tests you can create a non-Hilt application to use in your tests.

In non-Hilt applications, @OptionalInject allows you to disable Hilt injection in your @AndroidEntryPoint classes. However, note that disabling injection means your @Inject fields will then be null, so you usually need to check OptionalInjectCheck.wasInjectedByHilt(this) and do custom logic to populate those fields with whatever you want.

Again, doing this long-term for all your tests likely won't be a very pleasant experience, so it may be worth considering moving closer to the approach described in the Hilt's testing philosophy if possible.

EliottLujan commented 2 years ago

Thanks for the quick answer!

I can't believe I missed the @OptionalInject annotation. It seems to be exactly what we needed for tests.

There are trade offs indeed. For example, with @OptionalInject we won't be able to detect at compile time if a Fragment is displayed in an Activity that doesn't have @AndroidEntryPoint in the production code.

We'll consider using the Hilt's approach to test, probably with fake or mocks to replace the Repositories.

Thanks again! Closing the issue 😄