如何在Espresso的仪器测试中注入模拟的活动演示者

问题描述 投票:6回答:2

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

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

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

在我的HomeActivity的espressoTest中,我想注入一个模拟礼物。我还没有通过AppModule公开AppComponent内部的依赖关系。网络上大多数示例都这样做(因此,他们只是创建一个新的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;
    }
}

App

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

HomeActivity

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

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

android tdd dagger-2 android-espresso android-mvp
2个回答
0
投票

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

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


0
投票

解决该问题的关键是使用提供模拟PresenterDagger Module而不是HomeActivity仪器化测试中的“真实”模型。

为此,需要执行以下两个额外操作。

  1. 活动组件]的创建委托给某种抽象。
  2. 用仪器化测试替代抽象的实现(在应用程序“范围”中>]。]
  3. 在下面的示例中,我将使用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)

对于仪器化测试,创建扩展TestHomeComponentHomeComponent

@HomeScope
@Component(modules = [TestHomeModule::class])
interface TestHomeComponent : HomeComponent

TestHomeModule提供模拟Presenter

@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"
    ...
}

用法示例:

@RunWith(AndroidJUnit4::class)
class HomeActivityTest {
    private lateinit var mockPresenter: IHomeContract.Presenter

    @get:Rule
    val activityRule = ActivityTestRule(HomeActivity::class.java)

    @Before
    fun setUp() {
        mockPresenter = activityRule.activity.presenter
    }

    @Test
    fun activity_onCreate_presenter_should_onViewCreated() {
        verify(mockPresenter).someMethod()
    }
}

您可以在sample project中查看更多详细信息。

© www.soinside.com 2019 - 2024. All rights reserved.