gpt4 book ai didi

android - 对使用 kotlin 协程的改造调用进行单元测试

转载 作者:行者123 更新时间:2023-11-29 15:36:49 25 4
gpt4 key购买 nike

我正在使用 kotlin coroutineskotlin retrofit coroutines在我目前正在从事的项目中进行网络请求。但是我无法弄清楚如何为逻辑通过进行单元测试。

这是我的代码:

class WorklistInteractor @Inject
constructor(private val worklistRepository: WorklistRepository,
private val preferenceManager: PreferenceManager)
: NetworkInteractor, WorklistDialogContract.Interactor {

private var job = Job()

override fun getWorklist(listener: OnWorklistResultListener) {
job = launch(UI) {
val result = async {
worklistRepository.getWorklist(
ip = preferenceManager.worklistIp,
port = preferenceManager.worklistPort).awaitResult()
}.await()

when (result) {
//Successful HTTP result
is Result.Ok -> listener.onWorklistResult(result.value)
// Any HTTP error
is Result.Error -> {
Timber.e(result.exception, "HTTP error with code %s}", result.exception.code())
when(result.exception.code()) {
401 -> listener.onInvalidCredentialsFailure()
500 -> listener.internalServerError()
503 -> listener.noServerResponseFailure()
else -> listener.onError(result.exception.cause.toString())
}
}
// Exception while request invocation
is Result.Exception -> {
Timber.e(result.exception.cause, "Exception with cause %s", result.exception.cause.toString())
when(result.exception) {
is ConnectException -> listener.connectionRefused()
is SocketTimeoutException -> listener.failedToConnectToHost()
else -> listener.onError(result.exception.cause.toString())
}
}
}
}
}

override fun cancel() {
job.cancel()
}
}

这是我的单元测试之一:

@Test
fun `when worklistquery returns result, pass result back through listeners onWorklistResult`()
= runBlocking {

whenever(mWorklistRepositoryMock.getWorklist(anyString(), anyInt(), anyString()))
.thenReturn(Calls.response(expectedWorklistResult))

mInteractor.getWorklist(mOnWorklistResultListenerMock)

verify(mOnWorklistResultListenerMock).onWorklistResult(expectedWorklistResult)
verifyNoMoreInteractions(mOnWorklistResultListenerMock)
}

我在运行时不断收到以下消息:

Wanted but not invoked: onWorklistResultListener.onWorklistResult( ); -> at com.example.dialogs.worklistdialog.WorklistInteractorTest$when worklistquery returns result, pass result back through listeners OnWorklistResult()$1.doResume(WorklistInteractorTest.kt:58)

Actually, there were zero interactions with this mock.

最佳答案

您找到了解决方案,但也许对于其他人,尤其是初学者,解释您一开始为什么会出错以及为什么 runBlocking 有帮助可能会有所帮助。问题是,在运行单元测试时,期望这些测试是同步的,也就是说,如果一段时间后在某个单独的线程上执行任何代码,测试运行器永远不会知道这一点,因为对于测试运行器当测试运行程序线程上的方法调用完成时,测试完成。

因此无法测试不在主线程上运行的代码。事实上,尝试这样做甚至是一种不好的做法。由于无法保证在另一个线程上运行的代码何时完成(如果有的话),我们不知道此时主线程将处于什么状态(主线程甚至可能不再存在,就像这种情况一样)与单元测试运行器)。

即使以某种方式可以测试在其他线程中执行的代码,每次测试运行也不可避免地会有所不同(作为上一段的结果)并且测试可能会在每次运行时产生不同的结果。这直接违背了测试可靠并在每次运行中产生相同结果的意识形态。

因此在测试时,所有被测试的代码都需要在主线程上运行,并且应该确保永远不要尝试在测试中调用任何异步代码。

runBlocking 协程,毫不奇怪地在它启动的线程上以阻塞方式运行其中的代码(与 launch 相反,这将导致代码异步运行)。

所有这一切都需要注意,协程不是线程,但是如果您将上面文本中的单词 thread 替换为 asynchronous coroutine,文本将不会丢失它的任何含义。我所说的内容既适用于您使用传统线程的情况,也适用于您使用协程的情况。

关于android - 对使用 kotlin 协程的改造调用进行单元测试,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48091690/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com