【问题标题】:RoboGuice with Standard Android JUnit test cases带有标准 Android JUnit 测试用例的 RoboGuice
【发布时间】:2014-07-03 02:51:48
【问题描述】:

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

【问题讨论】:

  • 您找到解决方案了吗?我也想做同样的事情(主要是因为我设置 Roboelectric 失败)
  • 我在单元测试中遇到了同样的问题。你有任何进展吗@helleye
  • 这是一年多以前的事了。我相信她从下面的答案中对我有所帮助。但我不记得了。

标签: android junit roboguice


【解决方案1】:

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

显然,您需要将下面 sn-p 中的 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();
}

【讨论】:

  • 我相信是RoboGuice.util.reset();中的tearDown()
  • 不,不是。 Roboguice 中有一个内部 Util 类。
  • 你是对的,对于 RoboGuice 3。我正在用 RoboGuice 2 尝试这个。
  • 在我的主应用程序中将RoboGuice.setBaseApplicationInjector() 更改为RoboGuice.getOrCreateBaseApplicationInjector() 会在我的onCreate() 中抛出一个java.lang.NoClassDefFoundError: roboguice.RoboGuice 知道为什么吗?
【解决方案2】:

我已经设法让它以一种简单的使用方式工作,您只需使用 builder 在规则中绑定依赖项,以后可能会忘记它们,它会自行完成所有事情。您可能认为它过度设计,但如果您有许多内部包含 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);
        }
    }

}

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

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);
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-03-09
    • 2012-09-28
    • 1970-01-01
    • 2011-08-23
    • 1970-01-01
    • 2023-03-13
    • 2013-04-08
    相关资源
    最近更新 更多