9

我试图了解我应该如何测试我的应用程序,我仍在学习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但我不清楚你们中的任何人都可以提供一个例子或解释一下吗?

4

3 回答 3

1

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

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

让我们在这里谈谈类:

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

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

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

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

在这个名为 () 的场景中,我只添加了一个测试用例,test if books are displayed它模拟ViewContractModelContract初始化Presenter. finallyMockito.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

希望这可以帮助。

于 2019-05-18T01:57:49.053 回答
1
  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。使用规则允许您跨多个测试类重用初始化逻辑。

于 2019-12-31T04:46:35.917 回答
0

要为您的演示者编写单元测试,您应该: 1.在创建演示者对象进行测试时模拟myUseCaseprivate val myUseCase = mock<MyUseCase>() 2. addSchedulers.io() andAndroidSchedulers.mainThread() Schedulers.trampoline()`:to the constructor of the presenter then you can set

    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. 验证您的代码

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

于 2019-05-12T12:39:08.813 回答