你如何重写模块/依赖与匕首2.0单元测试? [英] How do you override a module/dependency in a unit test with Dagger 2.0?

查看:129
本文介绍了你如何重写模块/依赖与匕首2.0单元测试?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个<一个href="https://github.com/glombard/hello-dagger2/blob/master/hello-dagger2-simple/app/src/main/java/com/$c$cblast/hellodagger2/HelloActivity.java">simple Android的活动,提供一个单一的依赖。我的依赖注入到活动的的onCreate 是这样的:

I have a simple Android activity with a single dependency. I inject the dependency into the activity's onCreate like this:

Dagger_HelloComponent.builder()
    .helloModule(new HelloModule(this))
    .build()
    .initialize(this);

在我的 ActivityUnitTestCase 我要重写用的Mockito模拟的依赖。我想我需要使用测试专用模块,提供了模拟,但我无法弄清楚如何将此模块添加到对象图。

In my ActivityUnitTestCase I want to override the dependency with a Mockito mock. I assume I need to use a test-specific module which provides the mock, but I can't figure out how to add this module to the object graph.

在匕首1.x中这显然与像这样做:

In Dagger 1.x this is apparently done with something like this:

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

什么是匕首2.0当量以上的?

What's the Dagger 2.0 equivalent of the above?

您可以看到我的项目和它的单元测试<一href="https://github.com/glombard/hello-dagger2/blob/master/hello-dagger2-simple/app/src/androidTest/java/com/$c$cblast/hellodagger2/HelloActivityTest.java">here在GitHub上的。

You can see my project and its unit test here on GitHub.

推荐答案

也许这更是一种变通方法,对测试模块压倒一切适当的支持,但它允许重写生产模块的测试之一。下面的code片段显示简单的情况下,当你只有一个组成部分,一个模块,但这应该适用于任何场景。它需要大量的样板和code重复,所以要注意这一点。我敢肯定有会是一个更好的方式在未来实现这一目标。

Probably this is more a workaround that proper support for test module overriding, but it allows to override production modules with test one. The code snippets below shows simple case when you have just one component and one module, but this should work for any scenario. It requires a lot of boilerplate and code repetition so be aware of this. I'm sure there'll be a better way to achieve this in the future.

我还创建了一个项目实例居preSSO和Robolectric 。这个答案是基于包含在项目code。

I've also created a project with examples for Espresso and Robolectric. This answer is based on code contained in the project.

该解决方案需要两件事情:

The solution requires two things:

  • @Component 提供额外的二传手
  • 在测试组件必须延长生产部件
  • provide additional setter for @Component
  • test component must extend the production component

假设我们已经简单的应用程序象下面这样:

Assume we've simple Application like below:

public class App extends Application {

    private AppComponent mAppComponent;

    @Override
    public void onCreate() {
        super.onCreate();
        mAppComponent = DaggerApp_AppComponent.create();
    }

    public AppComponent component() {
        return mAppComponent;
    }

    @Singleton
    @Component(modules = StringHolderModule.class)
    public interface AppComponent {

        void inject(MainActivity activity);
    }

    @Module
    public static class StringHolderModule {

        @Provides
        StringHolder provideString() {
            return new StringHolder("Release string");
        }
    }
}

我们已经添加额外的方法应用类。这使我们能够更换生产组件。

We've to add additional method to App class. This allows us to replace the production component.

/**
 * Visible only for testing purposes.
 */
// @VisibleForTesting
public void setTestComponent(AppComponent appComponent) {
    mAppComponent = appComponent;
}

正如你可以看到的StringHolder 对象包含发行字符串值。该对象被注入到 MainActivity

As you can see the StringHolder object contains "Release string" value. This object is injected to the MainActivity.

public class MainActivity extends ActionBarActivity {

    @Inject
    StringHolder mStringHolder;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ((App) getApplication()).component().inject(this);
    }
}

在我们的测试中,我们要提供的StringHolder 与测试字符串。我们已经设定在应用测试组件之前类 MainActivity 创建 - 因为的StringHolder 注入了的onCreate 回调。

In our tests we want to provide StringHolder with "Test string". We've to set the test component in App class before the MainActivity is created - because StringHolder is injected in the onCreate callback.

在匕首V2.0.0组件可以扩展其他接口。我们可以利用这个来创建我们的 TestAppComponent 其中扩展 AppComponent

In Dagger v2.0.0 components can extend other interfaces. We can leverage this to create our TestAppComponent which extends AppComponent.

@Component(modules = TestStringHolderModule.class)
interface TestAppComponent extends AppComponent {

}

现在,我们能够定义我们的测试模块如 TestStringHolderModule 。最后一步是使用previously增加setter方法​​在应用类设置测试组件。这是重要的活动是创建之前做到这一点。

Now we're able to define our test modules e.g. TestStringHolderModule. The last step is to set the test component using previously added setter method in App class. It's important to do this before the activity is created.

((App) application).setTestComponent(mTestAppComponent);

居preSSO

有关长者preSSO我创建自定义的 ActivityTestRule 允许活动创建之前交换的组件。你可以找到$ C $下 DaggerActivityTestRule <一个href="https://github.com/tomrozb/dagger-testing/blob/master/app/src/androidTest/java/pl/dagger/testing/util/DaggerActivityTestRule.java">here.

For Espresso I've created custom ActivityTestRule which allows to swap the component before the activity is created. You can find code for DaggerActivityTestRule here.

与长者preSSO抽样检测:

Sample test with Espresso:

@RunWith(AndroidJUnit4.class)
@LargeTest
public class MainActivityEspressoTest {

    public static final String TEST_STRING = "Test string";

    private TestAppComponent mTestAppComponent;

    @Rule
    public ActivityTestRule<MainActivity> mActivityRule =
            new DaggerActivityTestRule<>(MainActivity.class, new OnBeforeActivityLaunchedListener<MainActivity>() {
                @Override
                public void beforeActivityLaunched(@NonNull Application application, @NonNull MainActivity activity) {
                    mTestAppComponent = DaggerMainActivityEspressoTest_TestAppComponent.create();
                    ((App) application).setTestComponent(mTestAppComponent);
                }
            });

    @Component(modules = TestStringHolderModule.class)
    interface TestAppComponent extends AppComponent {

    }

    @Module
    static class TestStringHolderModule {

        @Provides
        StringHolder provideString() {
            return new StringHolder(TEST_STRING);
        }
    }

    @Test
    public void checkSomething() {
        // given
        ...

        // when
        onView(...)

        // then
        onView(...)
                .check(...);
    }
}

Robolectric

这是一个与Robolectric感谢 RuntimeEnvironment.application

It's much easier with Robolectric thanks to the RuntimeEnvironment.application.

与Robolectric抽样检测:

Sample test with Robolectric:

@RunWith(RobolectricGradleTestRunner.class)
@Config(emulateSdk = 21, reportSdk = 21, constants = BuildConfig.class)
public class MainActivityRobolectricTest {

    public static final String TEST_STRING = "Test string";

    @Before
    public void setTestComponent() {
        AppComponent appComponent = DaggerMainActivityRobolectricTest_TestAppComponent.create();
        ((App) RuntimeEnvironment.application).setTestComponent(appComponent);
    }

    @Component(modules = TestStringHolderModule.class)
    interface TestAppComponent extends AppComponent {

    }

    @Module
    static class TestStringHolderModule {

        @Provides
        StringHolder provideString() {
            return new StringHolder(TEST_STRING);
        }
    }

    @Test
    public void checkSomething() {
        // given
        MainActivity mainActivity = Robolectric.setupActivity(MainActivity.class);

        // when
        ...

        // then
        assertThat(...)
    }
}

这篇关于你如何重写模块/依赖与匕首2.0单元测试?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆