简体   繁体   中英

Spying Activity with Mockito in Espresso tests with application using Dagger2 dependencies injection

I am very fresh on using the Dagger 2 in Android application. Currently we have application where the some parts of it is injected as dependencies. However, I cannot spy HomeActivity in our Espresso tests using this piece of code:

@LargeTest
@RunWith(AndroidJUnit4.class)

Public class ConnectionRobotTests {

private HomeRobot homeRobot = new HomeRobot();
private NetworkResults networkResults = new NetworkResults();

HomeActivity object;
SingleActivityFactory<HomeActivity> activityFactory =
    new SingleActivityFactory<HomeActivity>(HomeActivity.class) {
        @Override
        protected HomeActivity create(Intent intent) {
            object = spy(getActivityClassToIntercept());
            return object;
        }
    };

@Rule public ActivityTestRule<HomeActivity> testRule =
    new ActivityTestRule<>(activityFactory, true, true);

@AfterClass
public static void afterTest() {
    User.logout();
    Storage.clearAllPreferences();
}

@Test
public void connectAndDisconnectViaQuickConnect() {
    MockConnectionHelper.mockConnection(testRule);
    networkResults.isServerAvailable();

    homeRobot.connect().isConnectedTo();

    ConnectionResult result = homeRobot.disconnect();
    result.isDisconnected();
}

This the TestAppComponent.class:

@Singleton
@Component(modules = {AndroidSupportInjectionModule.class,  
ActivityBuilder.class, MockAppModule.class})
public interface TestAppComponent extends AppComponent {

   @Component.Builder
   interface Builder {

       @BindsInstance
       Builder application(TestApplication application);
       TestAppComponent build();
    }
}

The MockAppModule.class:

@Module
public class MockAppModule {

    @Singleton
    @Provides
    Gson provideGson() {
        return new Gson();
    }
}

TestApplication.class:

public class TestApplication extends MyApplication {
    @Override
    protected AndroidInjector<? extends DaggerApplication> applicationInjector() {
        return DaggerTestAppComponent.builder().application(this).build();
    }
}

When I run the test I get an error:

java.lang.RuntimeException: Unable to start activity ComponentInfo{com.application.android/com.application.android.ui.home.HomeActivity}: java.lang.IllegalArgumentException: No injector factory bound for Class<com.application.android.ui.home.HomeActivity$MockitoMock$1418108435>. Injector factories were bound for supertypes of com.application.android.ui.home.HomeActivity$MockitoMock$1418108435: [com.application.android.ui.home.HomeActivity]. Did you mean to bind an injector factory for the subtype?
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2913)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3048)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1808)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6669)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
Caused by: java.lang.IllegalArgumentException: No injector factory bound for Class<com.application.android.ui.home.HomeActivity$MockitoMock$1418108435>. Injector factories were bound for supertypes of com.application.android.ui.home.HomeActivity$MockitoMock$1418108435: [com.application.android.ui.home.HomeActivity]. Did you mean to bind an injector factory for the subtype?
at dagger.android.DispatchingAndroidInjector.inject(DispatchingAndroidInjector.java:104)
at dagger.android.AndroidInjection.inject(AndroidInjection.java:59)
at com.application.android.ui.home.HomeActivity.onCreate(HomeActivity.java:96)
at android.app.Activity.performCreate(Activity.java:7136)
at android.app.Activity.performCreate(Activity.java:7127)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1271)
at android.support.test.runner.MonitoringInstrumentation.callActivityOnCreate(MonitoringInstrumentation.java:667)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2893)

Is it something I am missing to add? Or should I approach spying of the HomeActivity differently? I was trying to add Injector factory for the HomeActivity, however it didn't changed anything. Does anybody have some suggestions what should be changed to spy HomeActivity?

The problem with spying on activity is that you can only provide AndroidInjector.Factory for a super class which is in this case HomeActivity, but Mockito creates a sub class HomeActivity$MockitoMock$... during Runtime.

From what i found so far - there is no possible way to create AndroidInjector.Factory for subclasses.

It is possible to mock AndroidInjector.Factory but considered a bad practice by Dagger developers themselves.

UPD : I ended up using Robolectric for testing lifecycle of activities\\services, check if it suits your needs as well.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM