繁体   English   中英

如何测试演示者 MVP Android

[英]How to test a presenter MVP Android

我试图了解我应该如何测试我的应用程序,我仍在使用mockito学习我也看到了mockk但无法使其工作,这是我的Presenter

class MyPresenterImpl @Inject constructor(var myUseCase: MyUseCase) : MyContract.Presenter {

    private var mView: MyContract.View? = null
    private var disposable: Disposable? = null


    override fun attachView(view: MyContract.View) {
        this.mView = view
        this.mView?.showProgressBar(true)
    }

    override fun loadResults() {

        disposable = getList.execute()
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(
                { result ->
                    mView?.showProgressBar(false)
                    mView?.showResults(result)
                },
                { error ->
                    mView?.showProgressBar(false)
                    mView?.showError(error.localizedMessage)
                })
    }

    override fun rxJavaUnsuscribe() {
        if (disposable != null && !disposable!!.isDisposed) {
            disposable!!.dispose()
        }
    }

    override fun detachView() {
        this.mView = null
    }

}

我应该如何测试这个演示者? 我是否必须添加所有这些方法?

我试图用mockito来做,但我也可以使用mockk

有些人告诉我,我必须对Schedulers做一些事情并使用trampoline但我不清楚你们中的任何人都可以提供一个例子或解释一下吗?

如果我正确理解了您的问题,那么您正在尝试了解如何使用单元测试(使用 Mockito)实现完整的 MVP 模式。

我写了一个示例代码(显示书籍列表的应用程序),它解释了一个基本的 MVP 实现,这里有一个 JUnit 测试用例: https : //github.com/harneev/AndroidMVPkt

让我们在这里谈谈类:

  1. ViewContract.kt - 接口定义方法,指导哑视图执行操作。
  2. ModelContract.kt - 接口定义方法以获取将封装在实现类下的数据(从数据库或从服务器)。
  3. Presenter.kt - 处理所有业务逻辑并通过作为参数注入的具体视图和模型来编排此逻辑。

注意:Presenter 是一个普通的类,业务逻辑编排器依赖于模型和视图。 一些开发人员喜欢将Presenter引用添加到View界面,但这种方式更简洁。

现在来看看这个MVP设计的单元测试用例 ( PresenterTest.kt )。

我使用mockito-kotlin作为模拟框架以获得更好的 kotlin 支持。

我在这个场景中只添加了一个名为test if books are displayed ViewContract () 的test if books are displayed ,它模拟ViewContractModelContract并初始化Presenter 最后Mockito.verify方法验证视图是否收到模型生成的书籍列表。

为了更好的单元测试用例,我总是将其分解为以下三个场景,解释如下:

// 1. given
how mocks will behave when their respective methods are called
// 2. when
when execution method is called
// 3. then
verify / assert if required action is performed

希望这可以帮助。

  1. 为测试包中的 junit 测试创建自定义规则TestSchedulerRule.kt

     class TestSchedulerRule(private val scheduler: Scheduler = Schedulers.trampoline()) : TestRule { override fun apply(base: Statement, d: Description): Statement { return object : Statement() { override fun evaluate() { RxJavaPlugins.setIoSchedulerHandler { scheduler } RxJavaPlugins.setComputationSchedulerHandler { scheduler } RxJavaPlugins.setNewThreadSchedulerHandler { scheduler } RxJavaPlugins.setSingleSchedulerHandler { scheduler } RxAndroidPlugins.setInitMainThreadSchedulerHandler { scheduler } RxAndroidPlugins.setMainThreadSchedulerHandler { scheduler } try { base.evaluate() } finally { RxJavaPlugins.reset() RxAndroidPlugins.reset() } } } } }
  2. 为您的演示者创建MyPresenterImplTest并使用创建的规则编写您需要的单元测试。 例如,我使用kotlin-mockitojunit4为演示者逻辑添加了一项测试。

     @RunWith(MockitoJUnitRunner::class) class MyPresenterImplTest { @Rule @JvmField val testRule = TestSchedulerRule() private val view: MyContract.View = mock() private val myUseCase: MyUseCase = mock() private val presenter = MyPresenterImpl(myUseCase) @Before fun setUp() { presenter.attachView(view) } @Test fun `WHEN btnLoad clicked EXPECT load and show results`() { //create needed results val results = listOf<Any>() //mock the result of execution myUseCase.invoke() whenever(myUseCase.invoke()).thenReturn(Single.just(results)) //trigger the needed action presenter.loadResults() //verify that all needed actions were called verify(myUseCase).invoke() verify(view).showResults(results) } }

关于规则的解释。

我们需要创建自定义测试规则,因为 AndroidSchedulers.mainThread() 返回的默认调度程序(当您在 Presenter 中编写 .observeOn(AndroidSchedulers.mainThread() 时)是 LooperScheduler 的一个实例,并且依赖于 JUnit 中不可用的Android 依赖项测试。

因此,我们需要在测试运行之前使用不同的调度程序初始化 RxAndroidPlugins。 使用规则允许您在多个测试类中重用初始化逻辑。

要为演示者编写单元测试,您应该: 1. mock myUseCase : private val myUseCase = mock<MyUseCase>() 2. add Schedulers.io() and AndroidSchedulers.mainThread() 添加to the constructor of the presenter then you can set在创建用于测试的演示者对象时to the constructor of the presenter then you can set Schedulers.trampoline()`:

    class MyPresenterImpl @Inject constructor(
        val myUseCase: MyUseCase,
        val ioScheduler: Scheduler = Schedulers,
        val uiScheduler: Scheduler = AndroidSchedulers.mainThread()
    ) : MyContract.Presenter

然后在测试的seUp()中:

    presenter = MyPresenterImpl(myUseCase, Schedulers.trampoline(), Schedulers.trampoline())
  1. 存根用例的函数execute()
    myUseCase.stub {
        on { execute() }.thenReturn(Single.just(xyz))
    }
  1. 验证您的代码

笔记:我更喜欢使用 Mockito 版本的Nhaarman

暂无
暂无

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

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