【发布时间】:2022-01-29 11:43:59
【问题描述】:
我已经为此苦苦挣扎了一段时间,也许有人可以帮助... 我在我的测试类中有这个功能:
fun launchForegroundTimer(context: Context) {
helper.log("AppRate", "[$TAG] Launching foreground count down [10 seconds]")
timerJob = helper.launchActionInMillisWithBundle(Dispatchers.Main, TimeUnit.SECOND.toMillis(10), context, this::showGoodPopupIfAllowed)
}
所以在那个函数中,我首先写入一些日志,然后调用一个协程函数,该函数需要一个 Dispatcher 参数,在运行动作之前等待多长时间,我想传递给动作的任何对象以及时间过去后调用的实际操作函数。
所以在这种情况下,类中的私有方法this::showGoodPopupIfAllowed 在经过 10,000 毫秒后被调用。
这是那个函数:
private fun showGoodPopupIfAllowed(context: Context?) {
if (isAllowedToShowAppRate()) {
showGoodPopup(context)
}
}
在第一个 if 中,在我可以调用 showGoodPopup(context) 之前进行了一系列检查
现在,这里是helper.launchActionInMillisWithBundle 函数:
fun <T> launchActionInMillisWithBundle(dispatcher: CoroutineContext, inMillis: Long, bundle: T, action: (T) -> Unit): Job = CoroutineScope(dispatcher).launchInMillisWithBundle(inMillis, bundle, action)
这里是实际的 CoroutineScope 扩展函数:
fun <T> CoroutineScope.launchInMillisWithBundle(inMillisFromNow: Long, bundle: T, action: (T) -> Unit) = this.launch {
delay(inMillisFromNow)
action(bundle)
}
我想要实现的是一个 UnitTest,它调用 launchForegroundTimer 函数,使用适当的参数调用辅助函数,并继续调用 lambda showGoodPopupIfAllowed 函数,我还可以为所有isAllowedToShowAppRate 中出现的 IF 语句。
目前我的测试在调用launchActionInMillisWithBundle 后立即停止并且测试刚刚结束。我假设没有真正调用任何协程,因为我在嘲笑 helper 类...不知道如何继续。
我阅读了一些有趣的文章,但似乎没有一篇能解决这种状态。 我目前的测试功能是这样的:
private val appRaterManagerHelperMock = mockkClass(AppRaterManagerHelper::class)
private val timerJobMock = mockkClass(Job::class)
private val contextMock = mockkClass(Context::class)
@Test
fun `launch foreground timer`() {
every { appRaterManagerHelperMock.launchActionInMillisWithBundle(Dispatchers.Main, TimeUnit.SECOND.toMillis(10), contextMock, any()) } returns timerJobMock
val appRaterManager = AppRaterManager(appRaterManagerHelperMock)
appRaterManager.launchForegroundTimer(contextMock)
verify(exactly = 1) { appRaterManagerHelperMock.log("AppRate", "[AppRaterManager] Launching foreground count down [10 seconds]") }
}
我使用 mockk 作为我的 Mocking 库。
AppRaterManager 是被测类
我还想提一下,理论上我可以将协程调用移到被测类之外。所以像activity.onResume() 这样的外部类可以启动某种倒计时,然后直接调用一个检查showGoodPopupIfAllowed() 的函数。但是目前,请假设我没有任何方法可以更改调用代码,因此计时器和协程应该保留在测试域中的类中。
谢谢!
【问题讨论】:
标签: android unit-testing kotlin lambda kotlin-coroutines