Last Updated: November 21, 2017
·
6.316K
· partition

Auto-injection of mocks using Mockito with RoboGuice & Robolectric

Aren't you tired with manually defining Guice's AbstractModule class just to make RoboGuice inject your mocks instead of real implementations?

If so, try this JUnit4 runner:
MocksInjectingTestRunner.java

public class MocksInjectingTestRunner extends RobolectricRoboTestRunner {

    public MyOwnTestRunner(Class<?> testClass) throws InitializationError {
        super(testClass);
    }

    @Override
    public void prepareTest(Object test) {
        super.prepareTest(test);
        MockitoAnnotations.initMocks(test);
        try {
            setupRoboguice(test, getListOfMocks(test));
        } catch (IllegalAccessException e) {
            throw new RuntimeException("Failed to get instance of object", e);
        }
    }

    private List<Object> getListOfMocks(Object test) throws IllegalAccessException {
        final Field[] declaredFields = test.getClass().getDeclaredFields();
        List<Object> objects = new ArrayList<Object>();
        for (Field field : declaredFields) {
            if (field.getAnnotation(Mock.class) != null) {
                field.setAccessible(true);
                objects.add(field.get(test));
            }
        }
        return objects;
    }

    private void setupRoboguice(Object test, List<Object> objects) {
        RoboGuice.setBaseApplicationInjector(Robolectric.application, RoboGuice.DEFAULT_STAGE,
                Modules.override(RoboGuice.newDefaultRoboModule(Robolectric.application))
                        .with(new MyRoboModule(objects)));

        RoboGuice.injectMembers(Robolectric.application, test);
    }

    public static class MyRoboModule extends AbstractModule {

        private List<Object> mocksToInject;

        public MyRoboModule(List<Object> mocksToInject) {
            this.mocksToInject = mocksToInject;
        }

        @Override
        protected void configure() {
            for (final Object mock : mocksToInject) {
                Class clazz = mock.getClass();
                bind(clazz.getSuperclass()).toInstance(mock);
            }
        }
    }
}

Example usage:
Registrar.java

public class Registrar {

    @Inject
    private HttpConnection httpConnection;

    public void register(User user) {
        // stuff
    }
}

HttpConnection.java

public class HttpConnection {

    public Result execute(Request httpRequest) {
        // stuff
        return null;
    }
}

And finally, our test class:
RegistrarTest.java

@RunWith(MocksInjectingTestRunner.class)
 public class RegistrarTest {

    @Mock
    private HttpConnection httpConnection;

    @Inject
    private Registrar registrar;

    @Test
    public void mockShouldBeNotNull() {
        assertNotNull(httpConnection);
    }

    @Test
    public void shouldInjectMock()  {
        assertEquals(httpConnection, registrar.getHttpConnection());
    }
}    

Enjoy!