How to exhaust an embedded object that is not declared in the module?

For dagger2 module

@Module public class MyModule { @Provides @Singleton public RestService provideRestService() { return new RestService(); } @Provides @Singleton public MyPrinter provideMyPrinter() { return new MyPrinter(); } } 

We could have a test module like Test

 public class TestModule extends MyModule { @Override public MyPrinter provideMyPrinter() { return Mockito.mock(MyPrinter.class); } @Override public RestService provideRestService() { return Mockito.mock(RestService.class); } } 

However, if for a class like below that is not declared in the dagger module ...

 public class MainService { @Inject MyPrinter myPrinter; @Inject public MainService(RestService restService) { this.restService = restService; } } 

How to create a MainService layout as described above.

Note, I do not plan to run the test for MainService according to the share in https://medium.com/@fabioCollini/android-testing-using-dagger-2-mockito-and-a-custom-junit-rule-c8487ed01b56#. 9aky15kke , but instead, my MainService is used in another normal class that I wanted to test. eg.

 public class MyClassDoingSomething() { @Inject MainService mainService; public MyClassDoingSomething() { //... } // ... public void myPublicFunction() { // This function uses mainService } } 
+5
source share
1 answer

This definitely does not answer your question, but, in my honest opinion, it is connected, it is useful and too large for comment.

I often come across this question, and I always end up doing a “constructor dependency injection”. This means that I no longer inject the field, annotating the field using @Inject , but passing the dependencies in the constructor like this:

 public class MyClassDoingSomething implements DoSomethig { private final Service mainService; @Inject public MyClassDoingSomething(Service mainService) { this.mainService = mainService; } } 

Notice how the constructor now receives this parameter and sets a field for it, and also annotates with @Inject ? I would also like these classes to implement an interface (also for MyService ). Among several other advantages that I find, it simplifies writing the dagger module:

 @Module public class DoSomethingModule { @Provides @Singleton public RestService provideRestService() { return new RestService(); } @Provides @Singleton public MyPrinter provideMyPrinter() { return new MyPrinter(); } @Provides @Singleton public Service provideMyPrinter(MyService service) { return service; } @Provides @Singleton public DoSomethig provideMyPrinter(MyClassDoingSomething something) { return something; } } 

(It is assumed that MyService implements or extends Service )

At the moment, it seems that you already know that the dagger is able to calculate the dependency graph by itself and build all the objects for you. So, what about unit testing of the MyClassDoingSomething class? I don’t even use a dagger here. I just provide the dependencies manually:

 public class MyClassDoingSomethingTest { @Mock Service service; private MyClassDoingSomething something; @Before public void setUp() throws Exception { MockitoAnnotations.init(this); something = new MyClassDoingSomething(service); } // ... } 

As you can see, the dependency is passed through the constructor manually.

Obviously, this does not work if you code something that does not have a constructor that can be called by you. Classic examples are android actions, fragments, or representations. There are ways to achieve this, but personally, I still think that you can somehow overcome this without a dagger. If you are testing a device that has an @Inject MyPresenter myPresenter , usually this field will have access to a package that works fine in tests:

 public class MyViewTest { @Mock MyPresenter presenter; private MyView view; @Before public void setUp() throws Exception { MockitoAnnotations.init(this); view.myPresenter = presenter; } } 

Please note that this only works if both MyViewTest and MyView are in the same package (which is often the case in Android projects).

At the end of the day, if you still want to use the dagger for tests, you can always create “test” modules and components that can be introduced by declaring methods in the component, for example:

 @Inject public interface MyTestComponent { void inject(MyClassDoingSomething something); } 

I find this ok-ish approach, but during my years of development, I prefer the first approach. It also reported problems with Robolectric that some configuration in the build.gradle file build.gradle required in order to get the kingger compiler to run for tests so that the classes are actually generated.

+1
source

All Articles