如何将模拟的演示者注入ActivityTest中。即使用意式浓缩咖啡进行仪器测试

时间:2018-06-29 22:27:07

标签: android tdd dagger-2 android-espresso android-mvp

我已经尝试了一个星期。而且,我已经检索了所有可用的文章,但它们的实现或示例不完善或在Espresso Tests的步骤中停了下来。

我的Android应用程序遵循MVP架构(并且使用Java)

场景:[仅举一个例子] 我有一个HomeActivity,使用Dagger2得到了HomePresenter。 (在HomeModule中通过void inject(HomeActivity activity)的{​​{1}}公开的HomeComponent中提供方法。

在我的HomeActivity的espressoTest中,我想注入一个模拟礼物。 我尚未通过AppModuleAppComponent内部公开此依赖性。网上的大多数示例都这样做(因此,他们只是创建了一个新的testApplication,然后执行Needfull)

我不想使用productFlavours方式注入或提供模拟类,因为它无法控制Mockito.when方法。

基本上。我想注入一个模拟演示者,为了对espresso进行单元测试,我可以在其中执行任何Mockito.when()操作。

我的代码在下面。

HomeComponent

@HomeScope
@Component(modules = HomeModule.class,dependencies = AppComponent.class)
public interface HomeComponent {
    void inject(HomeActivity activity);
}

HomeModule

@Module
public class HomeModule {

    private final IHomeContract.View view;

    public HomeModule(IHomeContract.View view) {
        this.view = view;
    }

    @Provides
    @HomeScope
    public IHomeContract.Presenter presenter(FlowsRepository flowsRepository, UserRepository userRepository, LoanRepository loanRepository) {
        return new HomePresenter(view, flowsRepository, userRepository, loanRepository);
    }

}

AppComponent

@Component(modules = {AppModule.class,RepositoryModule.class})
@AppScope
public interface AppComponent {
    void inject(App app);

    FlowsRepository flowRepository();
    LoanRepository loanRepository();
    UserRepository userRepository();
}

AppModule

@Module
public class AppModule {
    private Context appContext;

    public AppModule(@NonNull Context context) {
        this.appContext = context;
    }

    @Provides
    @AppScope
    public Context context() {
        return appContext;
    }
}

应用

component = DaggerAppComponent.builder()
                .appModule(new AppModule(this))
                .build();
        component.inject(this);

家庭活动

HomeComponent component = DaggerHomeComponent.builder()
                .appComponent(((App) getApplication()).getComponent())
                .homeModule(new HomeModule(this))
                .build();

再次。在我的测试(浓缩咖啡)中,我想注入Mockito的嘲笑的HomePresenter。这样我就可以对我的观点进行单元测试。

2 个答案:

答案 0 :(得分:7)

解决该问题的关键是要有一个 Dagger模块,它可以在HomeActivity的测试中提供模拟的 Presenter ,而不是“真实”。

为此,需要完成以下两个额外的操作(您可能还希望看到一个example )。

  1. HomeActivity Component 实例化为某种抽象。
  2. 在工具化测试中替代抽象的实现以提供模拟。

在下面的示例中,我将使用 Kotlin

定义委托接口:

interface HomeComponentBuilder {
    fun build(view: IHomeContract.View): HomeComponent
}

HomeComponent的初始化从HomeActivity移至委托实现:

class HomeComponentBuilderImpl constructor(private val app: App) : HomeComponentBuilder {

override fun build(view: IHomeContract.View): HomeComponent =
    DaggerHomeComponent.builder()
        .homeModule(HomeModule(view))
        .build()
}

使委托处于应用程序“作用域”中,以便您可以将其实现互换用于仪器测试:

interface App {
    val homeComponentBuilder: HomeComponentBuilder
    ...
}

App实现现在应包含

class AppImpl : Application(), App {
    override val homeComponentBuilder: HomeComponentBuilder by lazy {
        HomeComponentBuilderImpl(this@AppImpl)
    }
    ...
}

HomeActivity中的组件初始化如下:

(application as App)
        .homeComponentBuilder
        .build(this)
        .inject(this)

对于仪器化测试,请创建扩展TestHomeComponent的{​​{1}}:

HomeComponent

其中@HomeScope @Component(modules = [TestHomeModule::class]) interface TestHomeComponent : HomeComponent 提供了一个模拟 Presenter

TestHomeModule

剩下要做的就是制作一个测试委托实现

@Module
class TestHomeModule {

    @Provides
    fun providePresenter(): IHomeContract.Presenter = mock()
}

并在class TestHomeComponentBuilderImpl : HomeComponentBuilder { override fun build(view: IHomeContract.View): HomeComponent = DaggerTestHomeComponent.builder() .testTestHomeModule(TestHomeModule()) .build() }

中对其进行初始化
TestAppImpl

其余均为标准配置。创建使用class TestAppImpl : Application(), App { override val homeComponentBuilder: HomeComponentBuilder by lazy { TestHomeComponentBuilderImpl() } ... } 的自定义AndroidJUnitRunner

TestAppImpl

并将其添加到class TestAppRunner : AndroidJUnitRunner() { override fun newApplication(cl: ClassLoader?, className: String?, context: Context?): Application = Instrumentation.newApplication(TestAppImpl::class.java, context) } 模块app

build.gradle

用法示例:

defaultConfig {
    testInstrumentationRunner "your.package.TestAppRunner"
    ...
}

答案 1 :(得分:0)

所以。您的问题是您需要创建一个模块,该模块提供用于测试的模拟演示者,而不是“真实的”演示者。

这里有一篇很好的文章:Testing with Dagger