我试图了解如何测试我的应用程序,我还在学习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
让我们在这里谈谈类:
ViewContract.kt
- 接口定义方法,用于指导哑视图执行操作。ModelContract.kt
- 定义获取数据(从数据库或服务器)的方法的接口,这些数据将封装在实现类下。Presenter.kt
- 处理所有业务逻辑,并通过作为参数注入的具体视图和模型来编排此逻辑。
注意:表示器是常规类和业务逻辑业务流程协调程序,取决于模型和视图。一些开发人员喜欢
Presenter
View
接口添加引用,但这种方式更干净。
现在来看这个MVP设计的单元测试用例(PresenterTest.kt
)。
我正在使用 mockito-kotlin 作为更好的 kotlin 的模拟框架 支持。
在这种情况下,我只添加了一个名为test if books are displayed
() 的测试用例,它模拟ViewContract
和ModelContract
并初始化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
希望这有帮助。
-
为测试包中的 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() } } } } }
-
为演示者创建MyPresenterImplTest,并使用创建的规则编写所需的单元测试。例如,我使用kotlin-mockito和junit4为演示者逻辑添加了一个测试。
@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() 返回的默认调度程序(当您在演示器中编写 .observeOn(AndroidSchedulers.mainThread() 时)是 LooperScheduler的一个实例,并且依赖于 JUnit测试中不可用的 Android 依赖项。
因此,我们需要在测试运行之前使用不同的调度程序初始化RxAndroid插件。使用规则允许您跨多个测试类重用初始化逻辑。
若要为演示者编写单元测试,应: 1. 模拟myUseCase
:private val myUseCase = mock<MyUseCase>()
2. add
Schedulers.io()and
AndroidSchedulers.mainThread()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())
- 存根用例的函数
execute()
:
myUseCase.stub {
on { execute() }.thenReturn(Single.just(xyz))
}
- 验证您的代码
注意:我更喜欢使用Mockito版本的Nhaarman。