BlockHound
Esta página fue traducida por PageTurner AI (beta). No está respaldada oficialmente por el proyecto. ¿Encontraste un error? Reportar problema →
La extensión Kotest BlockHound activa el soporte para BlockHound en corrutinas. Ayuda a detectar código bloqueante en hilos de corrutinas no bloqueantes, por ejemplo cuando se llama accidentalmente a una función de biblioteca de E/S bloqueante en un hilo de interfaz de usuario.
Para usar esta extensión añade el módulo io.kotest.extensions:kotest-extensions-blockhound a la ruta de compilación de pruebas.
Primeros pasos
Registra la extensión BlockHound en tu clase de pruebas:
@DoNotParallelize
class BlockHoundSpecTest : FunSpec({
extension(BlockHound())
test("detects for spec") {
blockInNonBlockingContext()
}
})
La extensión BlockHound también puede registrarse por caso de prueba o a nivel de proyecto.
Este código es sensible a la concurrencia. Solo puede haber una instancia de esta extensión ejecutándose simultáneamente ya que surtirá efecto globalmente.
No puedes registrar la extensión BlockHound múltiples veces en diferentes niveles.
Usa @DoNotParallelize para pruebas habilitadas con BlockHound.
Detección
Las llamadas bloqueantes serán detectadas en hilos de corrutinas donde no se espera que bloqueen. Estos hilos son creados por el dispatcher predeterminado, como muestra este ejemplo:
private suspend fun blockInNonBlockingContext() {
withContext(Dispatchers.Default) {
@Suppress("BlockingMethodInNonBlockingContext")
Thread.sleep(2)
}
}
Por defecto, la extensión BlockHound producirá una excepción como esta cuando detecte una llamada bloqueante:
reactor.blockhound.BlockingOperationError: Blocking call! java.lang.Thread.sleep
at io.kotest.extensions.blockhound.KotestBlockHoundIntegration.applyTo$lambda-2$lambda-1(KotestBlockHoundIntegration.kt:27)
at reactor.blockhound.BlockHound$Builder.lambda$install$8(BlockHound.java:427)
at reactor.blockhound.BlockHoundRuntime.checkBlocking(BlockHoundRuntime.java:89)
at java.base/java.lang.Thread.sleep(Thread.java)
at io.kotest.extensions.blockhound.BlockHoundTestKt$blockInNonBlockingContext$2.invokeSuspend(BlockHoundTest.kt:17)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:570)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:750)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:677)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:664)
Al invocarlo como BlockHound(BlockHoundMode.PRINT), imprimirá las llamadas detectadas y continuará la prueba sin interrupciones.
Cuando se detecte una llamada bloqueante, puedes:
reemplazar la llamada por una no bloqueante (usando una biblioteca compatible con corrutinas), o
programar la corrutina llamante para que se ejecute en un hilo de E/S separado (por ejemplo mediante
Dispatchers.IO), oañadir una excepción si el bloqueo es inofensivo (ver más abajo).
Personalización
Para personalizar BlockHound, familiarízate con la documentación de BlockHound.
Las excepciones para llamadas bloqueantes consideradas inofensivas pueden añadirse mediante una clase BlockHoundIntegration separada como esta:
import reactor.blockhound.BlockHound
import reactor.blockhound.integration.BlockHoundIntegration
class MyBlockHoundIntegration : BlockHoundIntegration {
override fun applyTo(builder: BlockHound.Builder): Unit = with(builder) {
allowBlockingCallsInside("org.slf4j.LoggerFactory", "performInitialization")
}
}
Para permitir que BlockHound detecte y cargue automáticamente la integración, añade su nombre de clase completo en un archivo de configuración de proveedor de servicios:
resources/META-INF/services/reactor.blockhound.integration.BlockHoundIntegration.