繁体   English   中英

如何使用Dagger2将活动范围的依赖项替换为模拟

[英]How can I replace Activity scoped dependencies with mocks using Dagger2

我的Activity中有一个作用域依赖项,我想用一些模拟测试该活动。 我已经阅读了有关在测试期间建议用测试组件替换Application组件的不同方法,但我想要的是替换Activity组件。

例如,我想在我的MVP设置中测试针对模拟演示者的Activity。

我相信通过调用Activity上的setComponent()替换组件将不起作用,因为Activity依赖已经通过字段注入注入,因此在测试期间,将使用真实对象。

我该如何解决这个问题? Dagger1怎么样? 它有同样的问题吗?

注入组件

首先,创建一个静态类作为Activity的工厂。 我看起来有点像这样:

public class ActivityComponentFactory {

    private static ActivityComponentFactory sInstance;

    public static ActivityComponentFactory getInstance() {
        if(sInstance == null) sInstance = new ActivityComponentFactory();
        return sInstance;
    }

    @VisibleForTesting
    public static void setInstance(ActivityComponentFactory instance) {
        sInstance = instance;
    }

    private ActivityComponentFactory() {
        // Singleton
    }

    public ActivityComponent createActivityComponent() {
        return DaggerActivityComponent.create();
    }
}

然后只做ActivityComponentFactory.getInstance().createActivityComponent().inject(this); 在你的活动中。

对于测试,您可以在创建活动之前替换方法中的工厂。

提供嘲笑

正如@ EpicPandaForce的答案所表明的那样,这样做的官方支持方式目前涉及大量的样板和复制/粘贴代码。 Dagger 2团队需要提供一种更简单的部分覆盖模块的方法。

直到他们这样做,这是我的非正式方式: 只需扩展模块

假设您想用模拟替换ListViewPresenter。 假设您有一个PresenterModule,如下所示:

@Module @ActivityScope
public class PresenterModule {

    @ActivityScope
    public ListViewPresenter provideListViewPresenter() {
        return new ListViewPresenter();
    }

    @ActivityScope
    public SomeOtherPresenter provideSomeOtherPresenter() {
        return new SomeOtherPresenter();
    }
}

您可以在测试设置中执行此操作:

ActivityComponentFactory.setInstance(new ActivityComponentFactory() {
    @Override
    public ActivityComponent createActivityComponent() {
        return DaggerActivityComponent.builder()
                .presenterModule(new PresenterModule() {
                    @Override
                    public ListViewPresenter provideListViewPresenter() {
                        // Note you don't have to use Mockito, it's just what I use
                        return Mockito.mock(ListViewPresenter.class);
                    }
                })
                .build();
    }
});

......它只是有效

请注意,您不必包括@Provides上注释@Override方法。 事实上,如果你这样做,Dagger 2代码生成将失败。

这是有效的,因为模块只是简单的工厂 - 生成的Component类负责缓存作用域实例的实例。 @Scope注释由代码生成器使用,但在运行时无关紧要。

你不能在Dagger2中覆盖模块[ 编辑:你可以,只是不要在模拟上指定@Provides注释 ),这显然是正确的解决方案:只需使用builder().somethingModule(new MockSomethingModule()).build()并完成它!

如果您认为无法进行模拟,那么我会看到两个可能解决此问题的方法。 你可以使用模块来包含一个可插入的“提供者”,它可以改变它的实现(我不赞成这个,因为它太冗长了!)

public interface SomethingProvider {
    Something something(Context context);
}

@Module
public class SomethingModule {
    private SomethingProvider somethingProvider;

    public SomethingModule(SomethingProvider somethingProvider) {
        this.somethingProvider = somethingProvider;
    }

    @Provides
    @Singleton
    public Something something(Context context) {
        return somethingProvider.something(context);
    }
}

public class ProdSomethingProvider implements SomethingProvider {
    public Something something(Context context) {
        return new SomethingImpl(context);
    }
}

public class TestSomethingProvider implements SomethingProvider {
    public Something something(Context context) {
        return new MockSomethingImpl(context);
    }
}

SomethingComponent somethingComponent = DaggerSomethingComponent.builder()
    .somethingModule(new SomethingModule(new ProdSomethingProvider()))
    .build();

或者,您可以将提供的类和注入目标放入他们自己的“元组件”接口中,您的ApplicationComponentTestApplicationComponent将从该接口扩展。

public interface MetaApplicationComponent {
    Something something();

    void inject(MainActivity mainActivity);
}

@Component(modules={SomethingModule.class})
@Singleton
public interface ApplicationComponent extends MetaApplicationComponent {
}

@Component(modules={MockSomethingModule.class})
@Singleton
public interface MockApplicationComponent extends MetaApplicationComponent {
}

第三个解决方案就是像@vaughandroid的回答一样扩展模块。 请参考,这是正确的方法。

至于活动范围的组件......就像我在这里提到的那样,它只是一个不同的范围,真的。

我发现以下帖子解决了这个问题: http//blog.sqisland.com/2015/04/dagger-2-espresso-2-mockito.html

您首先需要允许修改活动的组件:

@Override public void onCreate() {
  super.onCreate();
  if (component == null) {
    component = DaggerDemoApplication_ApplicationComponent
        .builder()
        .clockModule(new ClockModule())
        .build();
  }
}

public void setComponent(DemoComponent component) {
  this.component = component;
}

public DemoComponent component() {
  return component;
}

并在测试用例中修改它

@Before
  public void setUp() {
    Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
    DemoApplication app
        = (DemoApplication) instrumentation.getTargetContext().getApplicationContext();
    TestComponent component = DaggerMainActivityTest_TestComponent.builder()
        .mockClockModule(new MockClockModule())
        .build();
    app.setComponent(component);
    component.inject(this);
  }

暂无
暂无

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

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