我正在尝试使用MVP编写一个应用程序,并调整我以前用Java编写的异步存储库模式以使用Kotlin的暂挂函数。但是,我无法正确测试使用暂停功能的代码。我得到的进一步结果是运行测试并失败了,原因是我相信模拟程序没有返回应该的对象,而是返回了null。
这是一个显示问题的小应用程序:UserRepository
(getUser()
方法在返回虚拟User和引发异常之间交替):
interface UserRepository {
suspend fun getUser(): User
}
class UserRepositoryImpl : UserRepository {
var shouldWork = false
override suspend fun getUser(): User {
shouldWork = !shouldWork
if (shouldWork) {
return User("Mr. User", "user@example.com")
} else {
throw UnableToFetchUserInfoException()
}
}
}
风景:
interface MainView {
fun showUserInfo(user: User)
fun hideUserInfo()
fun showFailedToLoadUserInfoIndicator()
fun hideFailedToLoadUserIndicator()
}
class MainActivity : AppCompatActivity(), MainView {
private lateinit var presenter: MainPresenter
override fun showUserInfo(user: User) {
userInfo.text = user.toString()
}
override fun hideUserInfo() {
userInfo.text = ""
}
override fun showFailedToLoadUserInfoIndicator() {
Toast.makeText(this, "Failed to get user info", Toast.LENGTH_SHORT).show()
}
override fun hideFailedToLoadUserIndicator() {
// nothing to do. It's a toast.
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
presenter = MainPresenterImpl(this, UserRepositoryImpl(), UI)
button.setOnClickListener {
presenter.onFetchUserButtonClicked()
}
}
}
主持人:
interface MainPresenter {
fun onFetchUserButtonClicked()
}
class MainPresenterImpl(private val view: MainView,
private val userRepository: UserRepository,
private val coroutineContext: CoroutineContext) : MainPresenter {
override fun onFetchUserButtonClicked() {
launch(coroutineContext) {
view.hideFailedToLoadUserIndicator()
try {
val user = userRepository.getUser()
view.showUserInfo(user)
} catch (ex: UnableToFetchUserInfoException) {
view.hideUserInfo()
view.showFailedToLoadUserInfoIndicator()
}
}
}
}
和测试:
@Test
fun `should show user info on the view when the user request finishes succesfully`() = runBlocking {
presenter = MainPresenterImpl(viewMock, userRepositoryMock, CommonPool)
val expectedUser = User("Test", "test@testaing.com")
whenever(runBlocking { userRepositoryMock.getUser() } ).thenReturn(expectedUser)
presenter.onFetchUserButtonClicked()
verify(viewMock, times(1)).showUserInfo(expectedUser)
}
哪个输出...
Argument(s) are different! Wanted:
mainView.showUserInfo(
User(name=Test, email=test@testaing.com)
);
-> at com.pablobr9.suspendwithtests.MainPresenterImplTest$should show user info on the view when the user request finishes succesfully$1.doResume(MainPresenterImplTest.kt:40)
Actual invocation has different arguments:
mainView.showUserInfo(
null
);
-> at com.pablobr9.suspendwithtests.MainPresenterImpl$onFetchUserButtonClicked$1.doResume(MainPresenterImpl.kt:15)
我已经尝试了很多东西,但仍然无法使用Kotlin中的暂停函数/协程编写可测试的MVP应用。如此简单的一种甚至都做不到。我在这里想念什么?
最佳答案
该修复程序已经在模仿库https://github.com/nhaarman/mockito-kotlin/pull/171中
验证您也已将mockito-core
明确地放入依赖列表中,例如:
dependencies {
// other dependencies...
// mockito...
testImplementation "org.mockito:mockito-core:2.13.0"
// mockito kotlin...
testImplementation "com.nhaarman:mockito-kotlin:1.5.0"
}