Mocking of the entered field in unit tests

I have a Presenter class that uses a field entered through Dagger, it looks something like this:

 public class RssListPresenter { @Inject RssService rssService; // <-- injected field public RssListPresenter() { setupDI(); } private void setupDI() { DaggerNetworkComponent.builder() .networkModule(new NetworkModule()) .build() .inject(this); } public void loadItems() { Rss rss = rssService.getRssFeed() // .... } } 

Everything works perfectly. Now, I would like to unit test the RssListPresenter class. The question is how to provide a mock RssService presentation to the presenter?

Of course, I can add a new setRssService(RssService rssService) method to the master and use it to provide a layout from unit tests, but adding this method only for unit tests does not seem right. What would be the right way to handle this?

For completeness, here are the declarations of modules and components:

 @Singleton @Component(modules = NetworkModule.class) public interface NetworkComponent { void inject(RssListPresenter presenter); } @Module public class NetworkModule { @Provides Retrofit provideRetrofit() { // ... } @Provides @Singleton RssService providePcWorldRssService(Retrofit retrofit) { return retrofit.create(RssService.class); } } 
+5
source share
2 answers

Injection properties like this are not so easy to verify. In this case, the constructor assembly is much better. Refactoring your constructor is as follows:

 private final RssService rssService; @Inject public RssListPresenter(RssService rssService) { this.rssService = rssService; } 

Now you can easily test it:

 //mocks RssService mockRssService; //system under test RssListPresenter rssListPresenter; @Before public void setup() { mockRssService = Mockito.mock(RssService.class); rssListPresenter = new RssListPresenter(mockRssService); } 

You should probably not use DaggerNetworkComponent.inject(this) inside RssListPresenter . Instead, you should configure the dagger so that when you introduce members to the top-level classes ( Activity , Fragment , Service ), he can access the graph of objects and create an instance of your RssPresenter .

Why just put the injectors in Activity and Service , and not something like RssListPresenter ? These are classes that are created by the Android system, so you have no choice but to use nozzles.

To clarify, Activity , Fragment , etc. are ideal injection targets . RssListPresenter etc. nested dependencies . You need to configure the dependency of the framework , the dagger so that it can provide the correct dependencies for the injection for the purpose of the injection.

So you also need to write the @Provides method for RssListPresenter

 @Provides provideRssListPresenter(RssService rssService) { return new RssListPresenteR(rssService); } 
+5
source

Your class violates some of the principles of SOLID , and this makes it very difficult for unit test. Your class is likely to violate SRP (single responsibility principle) because it has more than one reason for the change. There is also a possible violation of dependency inversion.

I advise you to rethink the model of classes, so that each of them performs a certain function and has one of the reasons for the change.

0
source

Source: https://habr.com/ru/post/1259339/


All Articles