테스트에서 정지함수를 호출하려면 코루틴이 있어야 하는데, JUnit 테스트 함수 자체는 정지함수가 아니다. 따라서 테스트 내에 코루틴 빌더를 이용하여, 새로운 코루틴을 생성한다.

runTest에서 테스트 코드를 래핑하면 기본 정지 함수를 테스트할 수 있고 코루틴의 지연을 자동으로 건너뛴다.
@Test
fun `delay는 자동으로 skip된다`() = runTest {
println("before test")
launch {
delay(5000)
println("launch1")
}
launch {
println("launch2")
}
println("after delay")
}

그러나 테스트 중인 코드에서 발생하는 상황에 따라 추가로 고려해야 할 사항이 있다.
runTest에서 만드는 최상위 코루틴 외에 새 코루틴을 만들 때는 적절한 TestDispatcher를 선택하여 새 코루틴이 예약되는 방식을 제어해야 한다.withContext 이용)하면 runTest는 일반적으로 계속 작동하지만 지연을 더 이상 건너뛰지 않으며 테스트 코드가 여러 스레드에서 실행되므로 예측 가능성이 떨어진다.테스트 디스패처는 테스트 목적으로 사용하는 CoroutineDispatcher의 구현이다. 새 코루틴의 실행을 예측할 수 있도록 테스트 중에 새 코루틴을 만드는 경우 TestDispatchers를 사용해야 한다.
테스트에서 사용하는 스케줄러 인스턴스는 하나만 있어야 하며, 모든 TestDispatchers 간에 공유되어야 한다. runTest는 테스트 코루틴을 시작하기 위해 TestScope를 만든다. TestDispatcher를 지정하지 않으면, TestScope는 기본적으로 StandardTestDispatcher를 만들고 이를 사용하여 최상위 코루틴을 실행한다.
StandardTestDispatcher 에서 새 코루틴을 시작하면 코루틴이 기본 스케줄러의 대기열에 추가되어 테스트 스레드를 사용할 수 있을 때마다 실행된다. 이러한 새 코루틴이 실행되도록 하려면 테스트 스레드를 생성해야 한다.
테스트 스레드가 최상위 테스트 코루틴(runTest)을 실행하는 동안 생성되지 않으면, 모든 새 코루틴은 테스트 코루틴이 완료된 후(하지만 runTest가 반환되기 전이다)에만 실행된다.
@Test
fun standardTest() = runTest {
val userRepo = UserRepository()
launch { userRepo.register("Alice") }
launch { userRepo.register("Bob") }
assertEquals(listOf("Alice", "Bob"), userRepo.getAllUsers()) // ❌ Fails
}
대기열에 추가된 코루틴이 실행되도록 테스트 코루틴을 생성하는 방법에는 여러가지가 있다.