如何在 Espresso 的仪器测试中注入模拟活动演示者 [英] How to inject Mocked Presenter of Activity in Instrumentation testing with Espresso

查看:45
本文介绍了如何在 Espresso 的仪器测试中注入模拟活动演示者的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经尝试了一个星期.我已经抓取了所有可用的文章,但它们的实现或示例不足或停留在 Espresso 测试的步骤上.

I have been trying this for a week. And I have crawled every article available but their implementations or examples fall short or stop at the steps of Espresso Tests.

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

My Android Application follows MVP architecture (And is in Java)

场景:[仅举一个例子]我有一个 HomeActivity,它使用 Dagger2 获取一个 HomePresenter.(提供通过 HomeComponent 中的 void inject(HomeActivity activity) 暴露的 HomeModule 中的方法.

Scenario: [Giving just one example] I have a HomeActivity which gets a HomePresenter using Dagger2. (Provides method in the HomeModule exposed through a void inject(HomeActivity activity) in the HomeComponent.

在我的 HomeActivity espressoTest 中,我想注入一个模拟礼物.我没有通过 AppComponentAppModule 中公开这个依赖项.网络上的大多数示例都做了哪些(所以他们只是创建一个新的 testApplication 然后做需要的)

In my espressoTest for HomeActivity I would like to inject a mockpresent. I Have not exposed this dependencies inside an AppModule through an AppComponent. which most examples on the net do (So they just create a new testApplication and then do the needfull)

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

I do not want to use the productFlavours way of injecting or providing mockclasses as it doesnt give me control over the Mockito.when methods.

所以基本上.我想注入一个模拟演示器,为了我在 espresso 中的单元测试,我可以在其中执行任何 Mockito.when() .

So basically. I would like to inject a mockpresenter wherein i can do whatever Mockito.when()s on it for the sake of my unit tests in espresso.

HomeComponent

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

家庭模块

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

}

应用组件

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

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

应用模块

@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.所以我可以对我的视图进行单元测试.

Once again. In my tests (espresso) i would like to inject a mockedHomePresenter the set by Mockito. So I can just unit test my views.

推荐答案

解决问题的关键是要有这样一个Dagger Module,它提供了一个模拟PresenterHomeActivity 的插桩测试中,而不是真实的"测试.

The key point in resolving the problem is to have such a Dagger Module that provides a mock Presenter in HomeActivity's instrumented test instead of the "real" one.

为此,需要执行以下 2 个额外操作(您可能还想查看 示例).

For this the following 2 extra actions need to be done (you might also want to see an example).

  1. HomeActivityComponent 的实例化委托给某种抽象.
  2. 替换检测测试中抽象的实现以提供模拟.
  1. Delegate instantiation of HomeActivity's Component to some abstraction.
  2. Substitute the implementation of the abstraction in instrumented tests to provide mocks.

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

I'll use Kotlin in the example below.

定义委托接口:

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

HomeComponent 初始化从 HomeActivity 移动到委托实现:

Move the HomeComponent initialisation from HomeActivity to the delegate implementation:

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

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

使委托位于应用程序范围"中,以便您可以交换其实现以进行检测:

Make the delegate be in application "scope" so that you could interchange its implementation for instrumented tests:

interface App {
    val homeComponentBuilder: HomeComponentBuilder
    ...
}

App 实现现在应该包含

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

HomeActivity 中的组件初始化如下所示:

Component initialisation in HomeActivity looks as follows:

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

对于插装测试,创建扩展 HomeComponentTestHomeComponent:

For instrumented testing create TestHomeComponent that extends HomeComponent:

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

其中 TestHomeModule 提供了一个模拟 Presenter

where TestHomeModule provides a mock Presenter

@Module
class TestHomeModule {

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

剩下要做的是实现测试委托

What's left to do is to make a test delegate implementation

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()
    }
    ...
}

其他都是标准的.创建一个使用 TestAppImpl 的自定义 AndroidJUnitRunner:

The rest is standard. Create a custom AndroidJUnitRunner that uses TestAppImpl:

class TestAppRunner : AndroidJUnitRunner() {
    override fun newApplication(cl: ClassLoader?, className: String?, context: Context?): Application = Instrumentation.newApplication(TestAppImpl::class.java, context)
}

并将其添加到 app 模块 build.gradle

and add it to app module 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()
    }
}

这篇关于如何在 Espresso 的仪器测试中注入模拟活动演示者的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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