I need clarification regarding using Dagger for unit tests on Android projects because I found two different opinions on the Dagger testing docs and Google Dagger code lab which are opposed to each other.
According to the Unit tests and manual instantiation section of Dagger testing docs:
It is generally recommended to create a Dagger component in your tests to instantiate objects, whether that is a larger test component for many tests or a small focused test component for the individual test.
According to the Unit tests section of Google code lab description:
You don't have to use Dagger-related code for unit tests. When testing a class that uses constructor injection, you don't need to use Dagger to instantiate that class. You can directly call its constructor passing in fake or mock dependencies directly just as you would if they weren't annotated.
The opinions do not conflict: they offer two choices to take depending on complexity.
The Dagger docs link to the Hilt testing philosophy page, which I'll summarize:
All that said, Dagger is explicitly designed to allow for explicit constructor calls as if you had written the factory code explicitly yourself:
The guiding principle is to generate code that mimics the code that a user might have hand-written to ensure that dependency injection is as simple, traceable and performant as it can be.
This also eases adoption into existing projects: unlike some other possible dependency injection solutions, you can write a class that can be called manually with explicit manual dependency injection, but then Dagger writes the implementations you would have written yourself.
The codelab, which is designed for illustrative usage from beginners, shows both cases: it shows that you can call the constructor yourself in a unit test, with a single mocked scopeless UserManager dependency, but then also shows how to configure an end-to-end test graph. The Dagger site acknowledges this possibility of direct constructor calls but asserts that outside of small toy problems, even unit tests will start to become too complex to warrant manual DI. (Try adding 7 more dependencies to LoginViewModel in the codelab, including a few scopes, then try refactoring it to reorder or remove dependencies. You might see what they mean, or lose some confidence in the completeness and accuracy of your test.) At that point you may want to use a tool like Hilt as it was designed, to ease construction in unit tests as well as integration and production environments.
In summary: the Dagger codelab shows a simple case and what you can do manually. The docs describe the eventual likely scaling problems, leading to what (they say) you should do eventually. There's no problem with letting both styles coexist in a codebase and migrating tests of large classes gradually as you see the need.