简体   繁体   English

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

[英]How to test mock interaction on Activity onResume() Using Dagger Modules and Robolectric?

I'm using Dagger for my dependency injection, it works well in my app but I have trouble to test it. 我正在使用Dagger进行依赖注入,它在我的应用程序中运行良好但我无法测试它。 I've followed this pattern in order to create the modules depenency graph : https://github.com/pyricau/shipfaster/blob/master/src/main/java/com/squareup/shipfaster/common/ShipFasterApplication.java 为了创建模块依赖图,我遵循了这种模式: https//github.com/pyricau/shipfaster/blob/master/src/main/java/com/squareup/shipfaster/common/ShipFasterApplication.java

Now, in my MainActivity test class, I want to be able to verify interaction with a mock when the Activity onResume() method is called. 现在,在我的MainActivity测试类中,我希望能够在调用Activity onResume()方法时验证与mock的交互。

Here is the class : 这是班级:

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

From what I can see, the onCreate() method is called but a real instance of myObject is used, not the mocked one. 从我所看到的,调用onCreate()方法,但使用myObject的真实实例,而不是myObject实例。 The test failed with a "wanted but not invoked - Actually, there were zero interactions with this mock." 测试失败了“想要但未被调用 - 实际上,与这个模拟没有交互。” error. 错误。

Maybe this is because the MainActivity I'm trying to create using Robolectric is not associated with my TestModule because it's created in the Application level, but I manage to make that test to pass by explicitly call a method on the MainActivity and put the myObject.doSomething() in there, but what I need is to test Android lifecycle calls. 也许这是因为我试图使用Robolectric创建的MainActivity与我的TestModule没有关联,因为它是在应用程序级别创建的,但我设法通过在MainActivity上显式调用方法并放置myObject来使该测试通过。 doSomething()在那里,但我需要的是测试Android生命周期调用。

Any idea on how can I manage to test this? 关于如何设法测试这个的任何想法?

The real object is used because I guess you have initialization of ObjectGraph in your Application class. 使用真实对象是因为我猜你在Application类中初始化了ObjectGraph When you call ((Application) getApplication()).inject(this) during tests you are using the same ObjectGraph as when you just run your application. 当您调用((Application) getApplication()).inject(this)在测试期间((Application) getApplication()).inject(this)时,您使用与运行应用程序时相同的ObjectGraph

In this test you are creating completly new ObjectGraph with mock instance of MyObject . 在这个测试中,您将使用MyObject模拟实例创建完全新的ObjectGraph This mock is injected only in MainActivityTest because when in MainActivity inject() is called it uses ObjectGraph made in Application . 此模拟仅在MainActivityTest注入,因为在MainActivity中调用inject()时,它使用在Application ObjectGraph

What you can do is to make TestApplication class (it has to have the same package as your Application class but needs to be in test directory) whitch extends your application and there add your TestModule to override real instances with mocks. 您可以做的是创建TestApplication类(它必须与您的Application类具有相同的包但需要在测试目录中),这会扩展您的应用程序并添加您的TestModule以覆盖具有模拟的实例。 For example in this way: 例如,以这种方式:

MyApplication.java MyApplication.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);
    }
}

TestMyApplication.java TestMyApplication.java

package com.example.myapp;

public class TestMyApplication extends MyApplication {

    @Override
    void init() {

    }

    @Override
    List<Object> getModules() {
        modules = super.getModules();
        modules.add(new TestModule());
        return modules;
    }
}

I had the same problems some time ago but I managed to solve it like this: Android Testing with Robolectric and Dagger 我前段时间遇到了同样的问题,但我设法解决了这个问题: 使用Robolectric和Dagger进行Android测试

WojciechKo suggestion may work in some cases but my solution can work without overriding the Application class in your tests.The difference is that you still need to provide a way to inject Dagger modules in your application rather than instantiating them in the Application class. WojciechKo建议可能在某些情况下有效但我的解决方案可以在您的测试中不覆盖Application类的情况下工作。区别在于您仍然需要提供一种方法来在应用程序中注入Dagger模块,而不是在Application类中实例化它们。 This way, in your test class you can add the TestModule to override the one that is used in the real Application class. 这样,在测试类中,您可以添加TestModule来覆盖真实Application类中使用的那个。

If you have problems with the solution presented in that link let me know and we can further investigate the problem. 如果您对该链接中提供的解决方案有疑问,请告知我们,我们可以进一步调查此问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM