当前位置: 首页 > 知识库问答 >
问题:

如何用Dagger2.0覆盖单元测试中的模块/依赖项?

松翔
2023-03-14
Dagger_HelloComponent.builder()
    .helloModule(new HelloModule(this))
    .build()
    .initialize(this);
@Before
public void setUp() {
  ObjectGraph.create(new TestModule()).inject(this);
}

上面的匕首2.0当量是多少?

您可以在GitHub上看到我的项目及其单元测试。

共有1个答案

商飞龙
2023-03-14

也许这是一个适当支持测试模块重写的解决方案,但它允许用测试一重写生产模块。下面的代码片段显示了只有一个组件和一个模块时的简单情况,但这应该适用于任何场景。它需要大量的样板和代码重复,所以要注意这一点。我相信将来会有更好的方法实现这一点。

我还为Espresso和Robolectric创建了一个示例项目。这个答案基于项目中包含的代码。

解决方案需要两件事:

  • @component
  • 提供附加的setter
  • 测试组件必须扩展生产组件

假设我们有一个简单的application,如下所示:

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

我们必须向app类添加其他方法。这允许我们替换生产组件。

/**
 * Visible only for testing purposes.
 */
// @VisibleForTesting
public void setTestComponent(AppComponent appComponent) {
    mAppComponent = appComponent;
}
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提供“test string”。在创建MainActivity之前,我们必须在App类中设置测试组件,因为StringHolder被注入到OnCreate回调中。

在DaggerV2.0.0中,组件可以扩展其他接口。我们可以利用这一点来创建我们的TestAppComponent,它扩展了AppComponent

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

}

现在我们可以定义测试模块,例如TestStringHolderModule。最后一步是使用app类中先前添加的setter方法设置测试组件。在创建活动之前这样做是很重要的。

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

意大利浓咖啡

对于Espresso,我创建了自定义的activitytestrule,它允许在创建活动之前交换组件。您可以在这里找到DaggerActivityTestRule的代码。

用浓缩咖啡进行样品测试:

@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(...);
    }
}
@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(...)
    }
}
 类似资料:
  • 问题内容: 在其中,您可以选择覆盖依赖项,并使其指向其他存储库,例如在以下https://github.com/kubermatic/glog- logrus 库中,您需要在Gopkg.toml文件中添加以下几行: 然后在代码库中。但是,在go模块中,我看不到这样的选择吗?这使我认为唯一的解决方案是将import更改为。 谢谢! 问题答案: 这就是指令的目的。 引用Wiki Go 1.11模块:我

  • 问题内容: 我有一段代码,我不知道如何进行单元测试!该模块使用urllib2从外部XML提要(twitter,flickr,youtube等)中提取内容。这是一些伪代码: 我的第一个想法是腌制响应并加载它以进行测试,但是显然urllib的响应对象是不可序列化的(它引发了异常)。 仅从响应主体保存XML是不理想的,因为我的代码也使用标头信息。它旨在作用于响应对象。 当然,在单元测试中依赖外部数据源是

  • 问题内容: 我试图在将其他模块作为依赖项的模块中进行单元测试控制器代码的单元化,但是还没有弄清楚如何正确模拟它们。 我正在使用Jasmine Framework,并使用Karma(Testacular)运行测试。 模块代码 规格代码 我得到的错误是Karma是“ no module af.widgets”,因此显然我没有对模块依赖项进行模拟。有什么提示吗? 问题答案: 如果要模拟声明一个或多个服务

  • 如何编写懒惰加载模块的单元测试用例 路由:导出常量路由:路由 = [ { 路径:",重定向到:'home',路径匹配:'完整' }, { 路径:'home',加载儿童:()= 规格文件: 它将路由器文件覆盖范围隐藏在spc中,但代码覆盖范围中未包含loadchild,因此如何实现100%的代码覆盖率是20%

  • 我可以在声纳获得单位测试覆盖率通过使用Jacoco工具的代码覆盖率,并使用其报告在声纳属性文件为'sonar.jacoco.report路径=.../Reports/report.exec'。如何通过使用RAD的默认插件获得SONAR中的单元测试覆盖率,该插件以. coveragedata、. Analysis和. html格式生成报告?