android / architecture-samples

A collection of samples to discuss and showcase different architectural tools and patterns for Android apps.
Apache License 2.0
44.49k stars 11.65k forks source link

[todo-mvp-dagger] Why do we have repository instantiated in tests? #423

Closed alouanemed closed 7 years ago

alouanemed commented 7 years ago

Can someone clarify this to me : Why do we have the TasksRepository instantiated in taskRepositoryTest instead of o having it inside a module, let's say DataModule added as a module to AppComponent.

Thank you !

digitalbuddha commented 7 years ago

When you write JVM unit tests you are putting a particular object under test. In this example it is the TaskRepository. If you notice both dependencies of TaskRepository are Mockito Mocks that are locally setup within the tests. You could in theory make a TestDataModule and a TestComponent but then you will only be providing a single configuration of TaskRepository with its dependencies to any test class using that module. Ideally you want to instead have each test class define exactly what it needs to test. Normal production code development wants to hide the implementation details of how an object and its dependencies are instantiated while in a test you want more control. When writing JVM unit tests I treat Dagger as YAGNI (You ain't going to need it).

The dagger documentation has a blurb about this as well, the preferred way to unit test code is by ignoring Dagger in tests.. https://google.github.io/dagger/testing.html

One of the benefits of using dependency injection frameworks like Dagger is that it makes testing your code easier. This document explores some strategies for testing applications built with Dagger.

Don’t use Dagger for unit testing

If you want to write a small unit test that tests one @Inject-annotated class, you don’t need to use Dagger in your test at all. Just call the @Inject-annotated constructor and methods and set the @Inject-annotated fields, if any, passing fake or mock dependencies directly.

final class ThingDoer {
  private final ThingGetter getter;
  private final ThingPutter putter;

  @Inject ThingDoer(ThingGetter getter, ThingPutter putter) {
    this.getter = getter;
    this.putter = putter;
  }

  String doTheThing(int howManyTimes) { /* … */ }
}

public class ThingDoerTest {
  @Test
  public void testDoTheThing() {
    ThingDoer doer = new ThingDoer(fakeGetter, fakePutter);
    assertEquals("done", doer.doTheThing(5));
  }
}

Hope that helps clarify :-)