我们在第六篇文章里面介绍了Dagger在单元测试里面的使用姿势。大致过程是这样的,首先,你要mock出一个Module,让它的某个Provider方法在被调用的时候,返回你想要mock的Dependency。然后使用这个mock的module来build出一个Component,再把这个Component放到你的ComponentHolder。举个例子说明一下,假设你有一个LoginActivity,里面有一个LoginPresenter,是通过Daggerinject进去的,如下:
publicclassLoginActivityextendsAppCompatActivity{
InjectLoginPresentermLoginPresenter;OverrideprotectedvoidonCreate(BundlesavedInstanceState){//...othercodeComponentHolder.getAppComponent().inject(this);}}//对应的Test类如下:RunWith(RobolectricGradleTestRunner.class)Config(constants=BuildConfig.class,sdk=1)publicclassLoginActivityTest{TestpublicvoidtestLogin(){AppModulemockAppModule=Mockito.mock(AppModule.class);LoginPresentermockLoginPresenter=mock(LoginPresenter.class);Mockito.when(mockAppModule.provideLoginPresenter(any(UserManager.class),any(PasswordValidator.class))).thenReturn(mockLoginPresenter);//当mockAppModule的provideLoginPresenter()方法被调用时,让它返回mockLoginPresenterAppComponentappComponent=DaggerAppComponent.builder().appModule(mockAppModule).build();//用mockAppModule来创建DaggerAppComponentComponentHolder.setAppComponent(appComponent);//假设你的Component是放在ComponentHolder里面的LoginActivityloginActivity=Robolectric.setupActivity(LoginActivity.class);((EditText)loginActivity.findViewById(R.id.username)).setText(xiaochuang);((EditText)loginActivity.findViewById(R.id.password)).setText(xiaochuangishandsome);loginActivity.findViewById(R.id.login).performClick();verify(mockLoginPresenter).login(xiaochuang,xiaochuangishandsome);}}可以看到,为了让Dagger返回一个Mock对象,我们需要写5行代码。再多写几个测试,我保证你一定会觉得繁琐的。当然,我们可以使用前一篇文章里面说的方式,和其它的一些手段,来简化代码,以下是我作出的一些努力,应该说,代码已经比较简洁了:
RunWith(RobolectricGradleTestRunner.class)Config(constants=BuildConfig.class,sdk=1)publicclassLoginActivityTest{RulepublicMockitoRulemockitoRule=MockitoJUnit.rule();MockLoginPresenterloginPresenter;TestpublicvoidtestLogin(){Mockito.when(TestUtils.appModule.provideLoginPresenter(any(UserManager.class),any(PasswordValidator.class))).thenReturn(loginPresenter);//当mockAppModule的provideLoginPresenter()方法被调用时,让它返回mockLoginPresenterTestUtils.setupDagger();LoginActivityloginActivity=Robolectric.setupActivity(LoginActivity.class);((EditText)loginActivity.findViewById(R.id.username)).setText(xiaochuang);((EditText)loginActivity.findViewById(R.id.password)).setText(xiaochuangishandsome);loginActivity.findViewById(R.id.login).performClick();verify(loginPresenter).login(xiaochuang,xiaochuangishandsome);}}publicclassTestUtils{publicstaticfinalAppModuleappModule=spy(newAppModule(RuntimeEnvironment.application));publicstaticvoidsetupDagger(){AppComponentappComponent=DaggerAppComponent.builder().appModule(appModule).build();ComponentHolder.setAppComponent(appComponent);}}上面把dagger设置相关的代码减少到了两行,应该说,已经不再是一个负担了。然而哪怕是这样,如果写多了的话,依然会让人感觉略烦,因为这也完全是Boilerplatecode(这里为什么要用“也”?)。再多写一点,你自然而然就会想,如果能有一个工具,能达到这样的效果就好了:我们在Test类里面定义一个
Mockfield(比如上面的loginPresenter),这个工具就能自动把这个field作为dagger的module对应的provider方法(provideLoginPresenter(...))的返回值。也就是说,自动的mockmodule,让它返回这个Mockfield,然后用这个mock的module来build一个这条巷道何时能退市还路白内障是否会变成青光眼呢