Search code examples
androidroboguiceandroid-espresso

Change injection modules for Espresso


I have an app that make some calls to a REST API. I am using Retrofit to implement the API and I am using Roboguice to inject my REST service where needed.

I am trying to write up a test suite using espresso. I want to use a custom injection module so I can mock responses for Retrofit using Mockito.

How can I change my test suite to use a custom injection module from Roboguice keeping espresso.

PS: I've seen how to do this with Roboelectric, but I am not using Roboelectric right now.


Solution

  • I stumbled upon the same problem and I couldn't find an easy solution for this online. After a day of tries and fails, I finally found a solution which works for me.

    You need to declare a custom ActivityTestRule class to override the Application Injector before the activity is launched. Here is an example :

    @RunWith(AndroidJUnit4.class)
    public class LoginActivityTest {
    
        protected final Api mApi = mock(Api.class);
        // declare the other mocks you want here
        protected final AbstractModule mTestModule = new MyTestModule();
    
        @Rule
        public ActivityTestRule<LoginActivity> mActivityRule = new RoboGuiceActivityTestRule<>(LoginActivity.class);
    
        private class RoboGuiceActivityTestRule<T extends Activity> extends ActivityTestRule<T> {
    
            public RoboGuiceActivityTestRule(Class<T> activityClass) {
                super(activityClass);
            }
    
            @Override
            protected void beforeActivityLaunched() {
                RoboGuice.overrideApplicationInjector((Application) InstrumentationRegistry.getTargetContext().getApplicationContext(), mTestModule);
            }
        }
    
        private class MyTestModule extends AbstractModule {
    
            @Override
            protected void configure() {
                bind(Api.class).toInstance(mApi);
                // bind the other mocks here
            }
        }
    
        @Test
        public void checkEmptyFormDoNotPerformLogin() throws Exception {
            onView(withId(R.id.etLogin)).perform(clearText());
            onView(withId(R.id.etPassword)).perform(clearText());
            onView(withId(R.id.btLogin)).perform(click());
            verify(mApi, times(0)).login("", "");
        }
    
        // ...
    }
    

    Of course, you can extract the class and pass the module to the constructor for a cleaner code.