如何使用Dagger模块和Robolectric在Activity onResume()上测试模拟交互?

时间:2014-12-15 13:55:42

标签: java android unit-testing robolectric dagger

我正在使用Dagger进行依赖注入,它在我的应用程序中运行良好,但我无法测试它。我已按照此模式创建模块依赖图:https://github.com/pyricau/shipfaster/blob/master/src/main/java/com/squareup/shipfaster/common/ShipFasterApplication.java

现在,在我的MainActivity测试类中,我希望能够在调用Activity onResume()方法时验证与mock的交互。

这是班级:

@Config(emulateSdk = 18)
@RunWith(RobolectricDaggerTestRunner.class)
public class MainActivityTest extends TestCase {

    @Inject MainActivity sut;
    public @Mock MyObject mockMyObject;

    @Before
    public void setUp() throws Exception {
        MockitoAnnotations.initMocks(this);
        ObjectGraph.create(new TestModule()).inject(this);
    }

    @Test
    public void testThatMyActivityDelegatesDoSomethingToMyObject(){
        //init
        ActivityController<MainActivity> activityController = ActivityController.of(sut);

        //run
        activityController.create().start().resume();

        //verify
        Mockito.verify(mockMyObject).doSomething();
    }

    @Module(
            includes = {ActivityModule.class},
            injects = MainActivityTest.class,
            overrides = true,
            library = true
    )
    class TestModule {
        @Provides
        MyObject provideMyObject() {
            return mockMyObject;
        }
    }
}

从我所看到的,调用了onCreate()方法,但使用的是myObject的实例,而不是模拟的实例。测试失败了“想要但未被调用 - 实际上,与这个模拟没有交互。”错误。

也许这是因为我尝试使用Robolectric创建的MainActivity与我的TestModule没有关联,因为它是在应用程序级别创建的,但是我设法通过在MainActivity上显式调用方法来使该测试通过并放入那里有myObject.doSomething(),但我需要的是测试Android生命周期调用。

关于如何设法测试这个的任何想法?

2 个答案:

答案 0 :(得分:1)

使用真实对象是因为我猜您在ObjectGraph课程中初始化了Application。在测试期间致电((Application) getApplication()).inject(this)时,您使用与运行应用程序时相同的ObjectGraph

在此测试中,您将使用模拟实例ObjectGraph创建完整的新MyObject。此模拟仅在MainActivityTest中注入,因为在调用MainActivity inject()时,它使用ObjectGraph中的Application

你可以做的是使TestApplication类(它必须与你的Application类具有相同的包但需要在测试目录中)whitch扩展你的应用程序并添加你的{{ 1}}用mocks覆盖实例。例如,以这种方式:

MyApplication.java

TestModule

TestMyApplication.java

package com.example.myapp;

public class MyApplication extends Application {

    ObjectGraph graph;
    private Account currentAccount;

    @Override
    public void onCreate() {
        super.onCreate();
        graph = ObjectGraph.create(getModules().toArray());
        init();
    }

    void init() {
        // initialization stuff should not be called in tests
    }

    List<Object> getModules() {
        List<Object> modules = new ArrayList<>();
        modules.add(new ActivityModule(this));
        return modules;
    }

    public void inject(Object object) {
        graph.inject(object);
    }
}

答案 1 :(得分:0)

前段时间我遇到了同样的问题,但我设法解决了这个问题: Android Testing with Robolectric and Dagger

WojciechKo建议可能在某些情况下有效但我的解决方案可以在您的测试中不覆盖Application类。不同之处在于您仍然需要提供一种在应用程序中注入Dagger模块的方法,而不是在Application类中实例化它们。这样,在测试类中,您可以添加TestModule来覆盖真实Application类中使用的那个。

如果您对该链接中提供的解决方案有疑问,请与我们联系,我们可以进一步调查此问题。