对 Kotlin 有点新并对其进行测试...我正在尝试使用挂起方法来测试 dao 对象包装器,该方法使用 awaitFirst() 作为 SQL 返回对象。然而,当我为它编写单元测试时,它只是陷入了一个循环。我认为这是因为 awaitFirst() 不在测试的同一范围内
实施:
suspend fun queryExecution(querySpec: DatabaseClient.GenericExecuteSpec): OrderDomain {
var result: Map<String, Any>?
try {
result = querySpec.fetch().first().awaitFirst()
} catch (e: Exception) {
if (e is DataAccessResourceFailureException)
throw CommunicationException(
"Cannot connect to " + DatabaseConstants.DB_NAME +
DatabaseConstants.ORDERS_TABLE + " when executing querySelect",
"querySelect",
e
)
throw InternalException("Encountered R2dbcException when executing SQL querySelect", e)
}
if (result == null)
throw ResourceNotFoundException("Resource not found in Aurora DB")
try {
return OrderDomain(result)
} catch (e: Exception) {
throw InternalException("Exception when parsing to OrderDomain entity", e)
} finally {
logger.info("querySelect;stage=end")
}
}
单元测试:
@Test
fun `get by orderid id, null`() = runBlocking {
// Assign
Mockito.`when`(fetchSpecMock.first()).thenReturn(monoMapMock)
Mockito.`when`(monoMapMock.awaitFirst()).thenReturn(null)
// Act & Assert
val exception = assertThrows<ResourceNotFoundException> {
auroraClientWrapper.queryExecution(
databaseClient.sql("SELECT * FROM orderTable WHERE orderId=:1").bind("1", "123") orderId
)
}
assertEquals("Resource not found in Aurora DB", exception.message)
}
我在 https://github.com/Kotlin/kotlinx.coroutines/issues/1204 上注意到了这个问题,但没有任何解决方法对我有用...
在单元测试中使用 runBlocking 只会导致我的测试永远无法完成。使用 runBlockingTest 会显式地抛出一个错误,指出“作业从未完成”……有人知道吗?此时有任何黑客攻击吗?
此外,我相当理解您不应该将挂起与块一起使用,因为这有点违背了挂起的目的,因为它释放线程以稍后继续,而阻塞会强制线程等待结果......但是那么这是如何工作的?
private suspend fun queryExecution(querySpec: DatabaseClient.GenericExecuteSpec): Map {
var result: Map<String, Any>?
try {
result = withContext(Dispatchers.Default) {
querySpec.fetch().first().block()
}
return result
}
这是否意味着 withContext 将使用一个新线程,并在其他地方重新使用旧线程?那么这并没有真正优化任何东西,因为无论产生一个新的上下文,我仍然会有一个被阻塞的线程?
答案 0 :(得分:0)
找到解决方案。
monoMapMock
是来自 Mockito 的模拟值。似乎 kotlinx-test 协程无法拦截异步以返回单声道。所以我强制我可以模拟的方法返回一个真正的 Mono 值而不是一个 Mocked Mono。这样做,正如路易斯所建议的那样。我不再嘲笑它并返回一个真正的价值
@Test
fun `get by orderid id, null`() = runBlocking {
// Assign
Mockito.`when`(fetchSpecMock.first()).thenReturn(Mono.empty())
Mockito.`when`(monoMapMock.awaitFirst()).thenReturn(null)
// Act & Assert
val exception = assertThrows<ResourceNotFoundException> {
auroraClientWrapper.queryExecution(
databaseClient.sql("SELECT * FROM orderTable WHERE orderId=:1").bind("1", "123") orderId
)
}
assertEquals("Resource not found in Aurora DB", exception.message)
}