runTest

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

Untitled

runTest에서 테스트 코드를 래핑하면 기본 정지 함수를 테스트할 수 있고 코루틴의 지연을 자동으로 건너뛴다.

		@Test
    fun `delay는 자동으로 skip된다`() = runTest {
        println("before test")
        launch {
            delay(5000)
            println("launch1")
        }

        launch {
            println("launch2")
        }

        println("after delay")
    }

Untitled

그러나 테스트 중인 코드에서 발생하는 상황에 따라 추가로 고려해야 할 사항이 있다.


TestDispatchers

테스트 디스패처는 테스트 목적으로 사용하는 CoroutineDispatcher의 구현이다. 새 코루틴의 실행을 예측할 수 있도록 테스트 중에 새 코루틴을 만드는 경우 TestDispatchers를 사용해야 한다.

테스트에서 사용하는 스케줄러 인스턴스는 하나만 있어야 하며, 모든 TestDispatchers 간에 공유되어야 한다. runTest는 테스트 코루틴을 시작하기 위해 TestScope를 만든다. TestDispatcher를 지정하지 않으면, TestScope는 기본적으로 StandardTestDispatcher를 만들고 이를 사용하여 최상위 코루틴을 실행한다.

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
}

대기열에 추가된 코루틴이 실행되도록 테스트 코루틴을 생성하는 방법에는 여러가지가 있다.