RoboGuice与标准Android JUnit测试用例

时间:2014-05-14 20:58:47

标签: android junit roboguice

我想在标准的Android JUnit检测测试用例中使用RoboGuice,并使用模拟覆盖我应用程序的一部分实际接线进行测试。我在网上找不到任何解释如何执行此操作的内容,因为我的所有搜索结果都通过RoboGuoice转到Robolectric。我没有使用Robolectric,也不能出于各种原因在我的应用程序中使用它。是否有人使用RoboGuice连接应用并为标准 Android Intrumentation测试用例注入了模拟?

2 个答案:

答案 0 :(得分:0)

我正在使用Roboguice 3,我使用标准setup中的以下teardownActivityInstrumentationTestCase2方法解决了这个问题。

显然,您需要使用自己的测试模块类替换下面代码段中的new TestModule()

@Override
protected void setUp() throws Exception {
    super.setUp();
    Application app = (Application)getInstrumentation().getTargetContext()
                      .getApplicationContext();
    RoboGuice.getOrCreateBaseApplicationInjector(app, RoboGuice.DEFAULT_STAGE, 
                   Modules.override(RoboGuice.newDefaultRoboModule(app))
                   .with(new TestModule()));
    getActivity();
}

@Override
protected void tearDown() throws Exception {
    RoboGuice.Util.reset();
    super.tearDown();
}

答案 1 :(得分:0)

我设法以简单的使用方式使其工作,您只需使用构建器绑定规则内的依赖关系,以后可能会忘记它们,它将自行完成所有操作。你可能认为它过度设计了,但如果tyou里面有很多带有robo guice依赖的测试类,那么重用它真的很好。 测试类中的用法如下:

@Rule
    public InjectWithMocksRule injectWithMocksRule = new InjectWithMocksRule(
            this,
            () -> new InjectRule
                    .BindingBuilder()
                    .add(MyClass.class, mockedClassImpl)
                    .add(SomeInterface.class, mockedInterfaceImpl));

我写了帮助类TestBindingModule:

public class TestBindingModule extends AbstractModule {

    private HashMap<Class<?>, Object> bindings = new HashMap<Class<?>, Object>();

    @Override
    @SuppressWarnings("unchecked")
    protected void configure() {
        Set<Entry<Class<?>, Object>> entries = bindings.entrySet();
        for (Entry<Class<?>, Object> entry : entries) {
            bind((Class<Object>) entry.getKey()).toInstance(entry.getValue());
        }
    }

    public void addBinding(Class<?> type, Object object) {
        bindings.put(type, object);
    }

    public void addBindings(HashMap<Class<?>, Object> bindings) {
        this.bindings.putAll(bindings);
    }

    public static void setUp(Object testObject, TestBindingModule module) {
        Module roboGuiceModule = RoboGuice.newDefaultRoboModule(RuntimeEnvironment.application);
        Module testModule = Modules.override(roboGuiceModule).with(module);
        RoboGuice.getOrCreateBaseApplicationInjector(RuntimeEnvironment.application, RoboGuice.DEFAULT_STAGE, testModule);
        RoboInjector injector = RoboGuice.getInjector(RuntimeEnvironment.application);
        injector.injectMembers(testObject);
    }

    public static void tearDown() {
        Application app = RuntimeEnvironment.application;
        DefaultRoboModule defaultModule = RoboGuice.newDefaultRoboModule(app);
        RoboGuice.getOrCreateBaseApplicationInjector(app, RoboGuice.DEFAULT_STAGE, defaultModule);
    }

}

比我使用自定义Rule让它变得简单:

public class InjectRule implements TestRule {

    public interface BindingBuilderFactory {
        BindingBuilder create();
    }

    public static class BindingBuilder {
        private HashMap<Class<?>, Object> bindings = new HashMap<>();

        public BindingBuilder add(Class<?> dependencyClass, Object implementation) {
            bindings.put(dependencyClass, implementation);
            return this;
        }

        HashMap<Class<?>, Object> buildBindings() {
            return this.bindings;
        }
    }

    private Object target;
    private BindingBuilderFactory bindingBuilderFactory;

    public InjectRule(Object target, BindingBuilderFactory bindingBuilderFactory) {
        this.target = target;
        this.bindingBuilderFactory = bindingBuilderFactory;
    }

    private void overrideTestInjections(Object target) {
        TestBindingModule module = new TestBindingModule();
        module.addBindings(this.bindingBuilderFactory.create().buildBindings());
        TestBindingModule.setUp(target, module);
    }

    @Override
    public Statement apply(Statement base, Description description) {
        return new StatementDecorator(base);
    }


    private class StatementDecorator extends Statement {

        private Statement baseStatement;

        StatementDecorator(Statement b) {
            baseStatement = b;
        }

        @Override
        public void evaluate() throws Throwable {
            before();
            try {
                baseStatement.evaluate();
            } catch (Error e) {
                throw e;
            } finally {
                after();
            }
        }

        void after() {
            TestBindingModule.tearDown();
        }

        void before() {
            overrideTestInjections(target);
        }
    }

}

此外,您可能希望在测试类中使用mocks注释初始化@Mock,因此您需要另一个自定义规则:

public class MockitoInitializerRule implements TestRule {

    private Object target;

    public MockitoInitializerRule(Object target) {
        this.target = target;
    }

    @Override
    public Statement apply(Statement base, Description description) {
        return new MockitoInitializationStatement(base, target);
    }

    private class MockitoInitializationStatement extends Statement {
        private final Statement base;
        private Object test;

        MockitoInitializationStatement(Statement base, Object test) {
            this.base = base;
            this.test = test;
        }

        @Override
        public void evaluate() throws Throwable {
            MockitoAnnotations.initMocks(test);
            base.evaluate();
        }
    }
}

最后,你想首先将它们组合到模拟模拟中,然后将它们设置为依赖项:

public class InjectWithMocksRule implements TestRule {

    private final RuleChain delegate;

    public InjectWithMocksRule(Object target, InjectRule.BindingBuilderFactory bindingBuilderFactory) {
        delegate = RuleChain
                .outerRule(new MockitoInitializerRule(target))
                .around(new InjectRule(target, bindingBuilderFactory));
    }

    @Override
    public Statement apply(Statement base, Description description) {
        return delegate.apply(base, description);
    }
}