Kotest BlockHound 확장
Kotest BlockHound 확장 프로그램은 코루틴에 대한 BlockHound 지원을 활성화한다. 이 확장 기능은 차단되지 않는 코루틴 스레드에서 차단 코드를 탐지하는 데 도움이 된다(예: UI 스레드에서 실수로 차단하는 I/O 라이브러리 함수를 호출하는 경우).
NOTE
이 확장 기능을 사용하려면 테스트 컴파일 경로에io.kotest:kotest-extensions-blockhound
모듈을 추가한다.
시작하기
테스트 클래스에 BlockHound
확장을 등록한다:
class BlockHoundSpecTest : FunSpec({
extension(BlockHound())
test("detects for spec") {
blockInNonBlockingContext()
}
})
BlockHound
확장은 테스트 케이스별로 또는 프로젝트 구성에서 등록할 수도 있다.
프로젝트 전체 또는 사양 전체에서 BlockHound
가 활성화된 경우 개별 테스트에 대해 비활성화할 수 있다:
test("allow blocking").config(extensions = listOf(BlockHound(BlockHoundMode.DISABLED))) {
blockInNonBlockingContext()
}
코드 섹션의 BlockHoundMode
를 변경할 수도 있다:
test("allow blocking section") {
// ...
withBlockHoundMode(BlockHoundMode.DISABLED) {
blockInNonBlockingContext()
}
// ...
}
탐지(Detection)
차단 호출은 차단하지 않을 것으로 예상되는 코루틴 스레드에서 탐지된다. 이러한 스레드는 이 예제에서 볼 수 있듯이 기본 디스패처에 의해 생성된다:
private suspend fun blockInNonBlockingContext() {
withContext(Dispatchers.Default) {
@Suppress("BlockingMethodInNonBlockingContext")
Thread.sleep(2)
}
}
BlockHound
확장 프로그램은 기본적으로 차단 호출를 탐지할 때마다 이와 같은 예외를 생성한다:
reactor.blockhound.BlockingOperationError: Blocking call! java.lang.Thread.sleep
at io.kotest.extensions.blockhound.KotestBlockHoundIntergration.applyTo$lambda-2$lambda-1(KotestBlockHoundIntergration.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)
NOTE
BlockHound(BlockHoundMode.PRINT)
로 호출하면 탐지된 호출을 출력하고 중단 없이 테스트를 계속한다.
블록킹 호출이 감지되면 다음과 같이 할 수 있다.
- 호출을 논블로킹 호출로 대체하거나(코루틴 인식 라이브러리 사용), 또는
- 호출 코루틴이 별도의 I/O 스레드에서 실행되도록 예약하거나(예:
Dispatchers.IO
를 통해), 또는 - 블로킹이 무해한 경우 예외를 추가한다(아래 참조).
사용자 지정
BlockHound를 사용자 지정하려면 BlockHound 문서를 숙지한다.
무해한 것으로 간주되는 호출을 차단하는 예외는 다음과 같이 별도의 BlockHoundIntergration
클래스를 통해 추가할 수 있다:
import reactor.blockhound.BlockHound
import reactor.blockhound.intergration.BlockHoundIntergration
class MyBlockHoundIntergration : BlockHoundIntergration {
override fun applyTo(builder: BlockHound.Builder): Unit = with(builder) {
allowBlockingCallsInside("org.slf4j.LoggerFactory", "performInitialization")
}
}
BlockHound
가 통합을 자동으로 감지하고 로드할 수 있도록 하려면, 서비스 공급자 구성 파일 resources/META-INF/services/reactor.blockhound.intergration.BlockHoundIntergration
에 정규화된 클래스 이름을 추가한다.