IT/Kotlin

[Kotlin/Coroutine] 7. Coroutine 작성시의 테스트와 디버깅

Hodie! 2023. 6. 19. 00:18
반응형

Coroutine의 유닛 테스팅

  • Coroutinesuspend Function들은 runblocking 코드블럭으로 수행하면된다.
  • 다만, 동적으로 Scope를 만드는 경우에는 Dispatchersparameter를 넘겨받는 ViewModel을 사용해야 한다.

Android Architecture Component와 함께 사용

  • Android Architecture Component와 함께 사용하면, LifeCycle 관리등 장점도 많이 있지만, 주의해야할 점들도 있다.
  • Andorid 특징을 고려해서는 Coroutine 코드는 Viewmodel에 놓는 것이 적합하다.

Job Debug Mode

Debug mode에서 JobtoString하면, 아래와 같은 형식으로 나온다.

“coroutine#1”:BlockingCoroutine{Active}@6d311334

Debugging Coroutine and Threads

  • Coroutine한 Thread에서 실행되어 다른 Thread에서 Resume될 수 있다.
  • 심지어 Single-Threaded Dispatcher의 경우에도 어떤 일을 어디서 언제 수행하는지 알아내기 힘들 수 있다.
  • 일반적인 Debugging 방법**Thread name을 Log로 출력**하는 것이다, 이는 Logging Framework를 통해 쉽게 할 수 있다,.
  • coroutine을 사용할 때, 쓰레드만 찍으면, context 정보를 충분히 알 수 없기 때문에, kotlinx.coroutinedebugging 용도로 함수들이 들어가 있다.
  • '-Dkotlinx.coroutines.debug' *JVM option 과 함께 아래 코드를 실행하면Thread.currentThread().name 만 출력해도 *main @coroutine#1” 과 같이 출력된다.
  • JVM 이 -ea 옵션으로 실행되는 한 debug mode 는 항상 켜져 있으며,
    debug mode 일 때는 coroutine#1 의 숫자는 순차적으로 assign 되어 출력된다.
fun log(msg: String) = println("[${Thread.currentThread().name}] $msg")
 
runBlocking{
    val a = async{
        log(“I’m a”)
        6
    }
    val b = async{
        log(“I’m b”)
        7
    }
    log(“answer is ${a.await() * b.await()}”)
}
  • 위의 경우 아래와 같이 3개의 Coroutine이 있다.
    1. answer 를 print 하는 main coroutine (#1)
    2. I’m a 를 print 하는 main coroutine (#2)
    3. I’m b 를 print 하는 main coroutine (#3)

Naming Coroutine For Debugging

  • 자동으로 Assign된 id도 로그를 자주 찍으면 상호관계를 보기에는 좋다.
  • 그러나, coroutine특정 request의 processing에 묶여있거나, 특정 background task를 수행한다면, Debug 용도로 이름을 주는 것이 좋다.
  • CoroutineNameContext ElementThread Name과 같은 기능을 한다.
    • 마찬가지로 Debugging mode가 켜져 있다면, thread name과 함께 표시된다.
runBlocking(CoroutineName(“main”)){
    log(“Started main coroutine”)
    val v1 = async(CoroutineName(“v1coroutine”)){
        delay(500L)
        log(“Computing v1”)
        252
    }
 
    val v2 = async(CoroutineName(“v2coroutine”)){
        delay(1000L)
        log(“Computing v2”)
        6
    }
 
    log(“The answer for v1 / v2 = ${v1.await() / v2.await(){“)
}
/* OUTPUT */
[main @main#1] Started main coroutine
[main @v1coroutine#2] Computing v1
[main @v2coroutine#3] Computing v2
[main #main#1] The answer for v1 / v2 = 42
반응형