๊นจ์•Œ ๊ฐœ๋… ๐Ÿ“‘/Android

[Android] Unit Testing - ๊ฐœ์š”์™€ ํ™˜๊ฒฝ ์„ค์ •

interfacer_han 2024. 7. 3. 16:20

#1 ์•ˆ๋“œ๋กœ์ด๋“œ ์•ฑ ํ…Œ์ŠคํŠธ

#1-1 ์•ˆ๋“œ๋กœ์ด๋“œ ์•ฑ ํ…Œ์ŠคํŠธ์˜ ์ข…๋ฅ˜

http://https//developer.android.com/training/testing/fundamentals#scope

๋จผ์ €, ์—ฌ๊ธฐ์— ์žˆ๋Š” ๊ตฌ๊ธ€ ๊ณต์‹ ๋ฌธ์„œ์—์„œ ์•ˆ๋“œ๋กœ์ด๋“œ ์•ฑ ํ…Œ์ŠคํŠธ์— ๋Œ€ํ•œ ๊ฐœ์š”๋ฅผ ์ฝ์œผ๋ฉด ์ข‹๋‹ค. ํ•ด๋‹น ๊ตฌ๊ธ€ ๊ณต์‹ ๋ฌธ์„œ์—์„œ ๋ณต์‚ฌํ•ด์˜จ ์œ„์˜ ๊ทธ๋ฆผ์€ ํ…Œ์ŠคํŠธ๋ฅผ ์ด 3๋‹จ๊ณ„๋กœ ๋‚˜๋ˆ„๊ณ  ์žˆ๋‹ค. ๋จผ์ € Unit test๋Š” ํ•จ์ˆ˜๋‚˜ ํด๋ž˜์Šค ๋“ฑ์˜ ์•ฑ์˜ ์•„์ฃผ ์ž‘์€ ๋ถ€๋ถ„์„ ๊ฒ€์ฆํ•˜๋Š” ํ…Œ์ŠคํŠธ๊ณ , ๋ณธ ๊ฒŒ์‹œ๊ธ€์—์„œ ๋‹ค๋ฃฐ ๋‚ด์šฉ์ด๋‹ค. ๋‘๋ฒˆ์งธ๋Š” Integration(ํ†ตํ•ฉ) test๋กœ, ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์—ฐ๋™, API ํ˜ธ์ถœ ๋“ฑ ๋ชจ๋“ˆ ๊ฐ„์˜ ์ƒํ˜ธ์ž‘์šฉ์„ ๊ฒ€์ฆํ•œ๋‹ค. ๋งˆ์ง€๋ง‰์€ End-to-end(๋๊ณผ ๋์„ ๋ถ™์ด๋Š”) test๋‹ค. ์ „์ฒด ์‹œ์Šคํ…œ์˜ ๋ชจ๋“  ๊ตฌ์„ฑ ์š”์†Œ(๋) ๊ฐ„์˜ ์ƒํ˜ธ์ž‘์šฉ(์ž˜ ๋ถ™๋Š” ์ง€)์„ ํ™•์ธํ•œ๋‹ค. End-to-end test์—์„œ์˜ '๊ตฌ์„ฑ ์š”์†Œ'๋Š” ์‚ฌ์šฉ์ž์˜ ์ž…๋ ฅ์ด๋‚˜ ์‹œ๋‚˜๋ฆฌ์˜ค ๋“ฑ๊นŒ์ง€ ํฌํ•จํ•œ๋‹ค. Integration test์™€ ์ด๋ฆ„์˜ ๋Šฌ์•™์Šค๋Š” ๋น„์Šทํ•˜์ง€๋งŒ, ์•„์ฃผ ๋„“์€ ๋ฒ”์œ„๋ฅผ ํ…Œ์ŠคํŠธํ•œ๋‹ค.
 

#1-2 ์•ˆ๋“œ๋กœ์ด๋“œ ์—๋ฎฌ๋ ˆ์ดํ„ฐ์™€ Unit Testing

์•ˆ๋“œ๋กœ์ด๋“œ ์ž…๋ฌธ์ž ์ž…์žฅ์—์„œ, ์•ˆ๋“œ๋กœ์ด๋“œ ํ”„๋กœ์ ํŠธ์—์„œ์˜ ํ…Œ์ŠคํŠธ๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ Android Virtual Device๋ฅผ ํ†ตํ•œ ํ™•์ธ์ด๋‹ค. ์ด๋Š” #1-1์˜ ๊ทธ๋ฆผ์—์„œ End-to-End test์˜ ํ•œ ์ข…๋ฅ˜๋ผ๊ณ  ๋ณผ ์ˆ˜ ์žˆ๋‹ค. ํ•˜์ง€๋งŒ ์ด๋Š” ์‚ฌ์šฉ์ž ๊ฒฝํ—˜ ์œ„์ฃผ์˜ ํ™•์ธ์ธ๋ฐ๋‹ค๊ฐ€, ํ•„์š”์—†๋Š” ๋ถ€๋ถ„๊นŒ์ง€ ํฌํ•จํ•ด ํ…Œ์ŠคํŠธํ•˜๊ฒŒ ๋œ๋‹ค. ์ฆ‰, ์•ฑ์„ ํ†ต์งธ๋กœ ํ…Œ์ŠคํŠธํ•˜๋Š” ์–ด์ฐŒ๋ณด๋ฉด ์•ฝ๊ฐ„ ๋ฌด์‹ํ•œ ๋ฐฉ๋ฒ•์ด๋‹ค. ์ด๋•Œ ์•ˆ๋“œ๋กœ์ด๋“œ์—์„  ๋˜ ๋‹ค๋ฅธ ํ…Œ์ŠคํŠธ ๋ฐฉ๋ฒ•์„ ์ œ๊ณตํ•˜๋Š”๋ฐ, ์ด ๋ฐฉ๋ฒ•๋“ค์€ ํ”„๋กœ์ ํŠธ๋ฅผ ๋ถ€๋ถ„(Unit)์ ์œผ๋กœ ํ…Œ์ŠคํŠธํ•˜๊ฒŒ ๋งŒ๋“ค์–ด์ค€๋‹ค.
 

#2 ์•ˆ๋“œ๋กœ์ด๋“œ Unit Testing์˜ ์ข…๋ฅ˜

#2-1 Local unit test

 

๋กœ์ปฌ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ ๋นŒ๋“œ  |  Android Developers

์ด ํŽ˜์ด์ง€๋Š” Cloud Translation API๋ฅผ ํ†ตํ•ด ๋ฒˆ์—ญ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๋กœ์ปฌ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ ๋นŒ๋“œ ์ปฌ๋ ‰์…˜์„ ์‚ฌ์šฉํ•ด ์ •๋ฆฌํ•˜๊ธฐ ๋‚ด ํ™˜๊ฒฝ์„ค์ •์„ ๊ธฐ์ค€์œผ๋กœ ์ฝ˜ํ…์ธ ๋ฅผ ์ €์žฅํ•˜๊ณ  ๋ถ„๋ฅ˜ํ•˜์„ธ์š”. ๋กœ์ปฌ ํ…Œ์ŠคํŠธ๋Š” Android ๊ธฐ๊ธฐ๋‚˜ ์—

developer.android.com

JVM(Java Virtual Machine)์„ ์‚ฌ์šฉํ•˜์—ฌ ๋น ๋ฅธ ํ…Œ์ŠคํŠธ๋ฅผ ์‹คํ–‰ํ•œ๋‹ค. ์ฆ‰, Android ์—๋ฎฌ๋ ˆ์ดํ„ฐ์™€๋Š” ๊ด€๋ จ์ด ์—†๋‹ค. ๊ทธ๋ ‡๋‹ค๊ณ  Android ํ”„๋ ˆ์ž„์›Œํฌ์™€ ๊ด€๋ จ๋œ ํ…Œ์ŠคํŠธ๋ฅผ ํ•  ์ˆ˜ ์—†๋‹ค๋Š” ๋ง์€ ์•„๋‹ˆ๋‹ค. Context์™€ ๊ฐ™์ด Android์˜ ์‹ค์ œ ๋Ÿฐํƒ€์ž„ ํ™˜๊ฒฝ๊ณผ ๊ด€๋ จ๋œ ๊ฐœ๋…์— ๋Œ€ํ•œ ํ…Œ์ŠคํŠธ ๋“ฑ์€ ์ง„ํ–‰ํ•˜์ง€ ๋ชปํ•˜์ง€๋งŒ, ViewModel๊ณผ ๊ฐ™์ด UI ๋ฐ ์•ˆ๋“œ๋กœ์ด๋“œ ํ”„๋ ˆ์ž„์›Œํฌ์™€์˜ ์˜์กด์„ฑ์ด ์ ์€ ๊ฐ์ฒด๋Š” ํ…Œ์ŠคํŠธ๊ฐ€ ๊ฐ€๋Šฅํ•˜๋‹ค. ์™œ๋ƒํ•˜๋ฉด ํ•„์š”ํ•œ ๊ฒฝ์šฐ Dependency๋ฅผ Test double๋กœ ๋‘ฌ๋ฒ„๋ฆฌ๋ฉด ๊ทธ๋งŒ์ด๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ๊ฒŒ๋‹ค๊ฐ€, Robolectric๋‚˜ Mockito์™€ ๊ฐ™์€ Unit Test์šฉ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” Android ํ”„๋ ˆ์ž„์›Œํฌ์˜ ์ผ๋ถ€๋ฅผ ๋ชจ๋ฐฉํ•˜๊ฑฐ๋‚˜ ์ƒํ˜ธ์ž‘์šฉ๋ฅผ ๊ฐ€๋Šฅ์ผ€ ๋งŒ๋“ค์–ด์ฃผ์–ด Local unit test์˜ ํ•œ๊ณ„๋ฅผ ๊ฝค๋‚˜ ์ค„์—ฌ์ค€๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ด๋ ‡๊ฒŒํ•ด๋„ ํ…Œ์ŠคํŠธํ•  ์ˆ˜ ์—†๋Š” ์ƒํ™ฉ์ด๋ผ๋ฉด ์•„๋ž˜์— ์žˆ๋Š” Instrumented test๋กœ ํ…Œ์ŠคํŠธํ•œ๋‹ค. Local unit test ์ˆ˜ํ–‰์„ ์œ„ํ•ด ์กด์žฌํ•˜๋Š” "ํ”„๋กœ์ ํŠธ๋ช…/๋ชจ๋“ˆ๋ช…/src/test/java"๋ผ๋Š” ์ „์šฉ ๋””๋ ‰ํ† ๋ฆฌ๊ฐ€ ์•ˆ๋“œ๋กœ์ด๋“œ ํ”„๋กœ์ ํŠธ์— ์žˆ๋‹ค.
 

#2-2 Instrumented test

 

๊ณ„์ธก ํ…Œ์ŠคํŠธ ๋นŒ๋“œ  |  Android Developers

์ด ํŽ˜์ด์ง€๋Š” Cloud Translation API๋ฅผ ํ†ตํ•ด ๋ฒˆ์—ญ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๊ณ„์ธก ํ…Œ์ŠคํŠธ ๋นŒ๋“œ ์ปฌ๋ ‰์…˜์„ ์‚ฌ์šฉํ•ด ์ •๋ฆฌํ•˜๊ธฐ ๋‚ด ํ™˜๊ฒฝ์„ค์ •์„ ๊ธฐ์ค€์œผ๋กœ ์ฝ˜ํ…์ธ ๋ฅผ ์ €์žฅํ•˜๊ณ  ๋ถ„๋ฅ˜ํ•˜์„ธ์š”. ๊ณ„์ธก ํ…Œ์ŠคํŠธ๋Š” ์‹ค์ œ ๊ธฐ๊ธฐ ๋˜๋Š” ์—๋ฎฌ

developer.android.com

#2-1 ๋‹ฌ๋ฆฌ, Android ๊ธฐ๊ธฐ์—์„œ ์‹คํ–‰๋œ๋‹ค. ๋”ฐ๋ผ์„œ Android ํ”„๋ ˆ์ž„์›Œํฌ API๋ฅผ ์ง์ ‘ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ๋”ฐ๋ผ์„œ Local unit test์— ๋น„ํ•ด ๋” ๋†’์€ ์‹ ๋ขฐ์„ฑ & ์ถฉ์‹ค๋„๋ฅผ ์ง€๋‹Œ๋‹ค. ํ•˜์ง€๋งŒ ํ›จ์”ฌ ๋А๋ฆฌ๋ฏ€๋กœ Local unit test๊ฐ€ ๋ถˆ๊ฐ€๋Šฅํ•œ ๋•Œ์˜ ์„ ํƒ์ง€๋กœ ๋‘๋Š” ๊ฒƒ์ด ์ข‹๋‹ค. Instrumented test๋ฅผ ์œ„ํ•ด ์กด์žฌํ•˜๋Š” Instrumentation๋ผ๋Š” ํด๋ž˜์Šค๊ฐ€ ์žˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๋ชจ๋‹ˆํ„ฐ๋งํ•˜๋ฉด์„œ Activity, Service, BroadcastReceiver ๋“ฑ์„ ์‹คํ–‰ํ•˜๊ฑฐ๋‚˜, ๊ธฐ๊ธฐ์˜ ๋ฒ„ํŠผ ํด๋ฆญ์ด๋‚˜ ์Šคํฌ๋ฆฐ ํ„ฐ์น˜ ๋“ฑ์˜ ์‚ฌ์šฉ์ž ์ž…๋ ฅ ๋˜ํ•œ ์‹œ๋ฎฌ๋ ˆ์ด์…˜ ๊ฐ€๋Šฅํ•˜๋‹ค. Instrumented test ์ˆ˜ํ–‰์„ ์œ„ํ•ด ์กด์žฌํ•˜๋Š” "ํ”„๋กœ์ ํŠธ๋ช…/๋ชจ๋“ˆ๋ช…/src/androidTest/java"๋ผ๋Š” ์ „์šฉ ๋””๋ ‰ํ† ๋ฆฌ๊ฐ€ ์•ˆ๋“œ๋กœ์ด๋“œ ํ”„๋กœ์ ํŠธ์— ์žˆ๋‹ค.
 

#3 Unit test๋ฅผ ์œ„ํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋‹ค์šด๋กœ๋“œ

#3-1 dependency์˜ ์ข…๋ฅ˜

plugins {
    ...
}

android {
    ...
}

dependencies {

    implementation("androidx.core:core-ktx:1.9.0")
    implementation("androidx.appcompat:appcompat:1.7.0")
    implementation("com.google.android.material:material:1.12.0")
    implementation("androidx.constraintlayout:constraintlayout:2.1.4")
    testImplementation("junit:junit:4.13.2")
    androidTestImplementation("androidx.test.ext:junit:1.2.1")
    androidTestImplementation("androidx.test.espresso:espresso-core:3.6.1")
}

์•ˆ๋“œ๋กœ์ด๋“œ ์ŠคํŠœ๋””์˜ค์—์„œ [File] - [New] - [New Project] - [Empty Views Activity]ํ•  ๋•Œ, ๋ชจ๋“ˆ ์ˆ˜์ค€ build.gradle.kts์— ๊ธฐ๋ณธ์ ์œผ๋กœ ๋“ค์–ด๊ฐ€์žˆ๋Š” dependency๋‹ค. ํฐ ๋”ฐ์˜ดํ‘œ(") ์‚ฌ์ด์— ์žˆ๋Š” ์ข…์†์„ฑ์˜ ๋ฌธ์ž์—ด ์‹๋ณ„์ž ๊ทธ๋ฆฌ๊ณ  ๊ทธ ์ข…์†์„ฑ์˜ ๊ตฌํ˜„ ๋ฐฉ๋ฒ•์„ ์ •์˜ํ•œ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ, ์ข…์†์„ฑ์˜ ๊ตฌํ˜„ ๋ฐฉ๋ฒ•์ด ํ•˜๋‚˜๊ฐ€ ์•„๋‹Œ ๋ชจ์Šต์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค. ์—ฌ๊ธฐ์„œ๋Š” implementation, testImplementation, androidTestImplementation์˜ 3๊ฐ€์ง€๋กœ ๋ฒ”์ฃผ๊ฐ€ ๋‚˜๋‰˜์–ด์ ธ ์žˆ๋‹ค.
 
implementation์€ ํ”„๋กœ์ ํŠธ์˜ ๋ชจ๋“  ๊ณณ์—์„œ ์ข…์†์„ฑ(Dependency)์„ ์ œ๊ณตํ•œ๋‹ค. testImplementation์€ Local unit test์—๊ฒŒ๋งŒ ์ข…์†์„ฑ์„ ์ œ๊ณตํ•œ๋‹ค. ์ด ๋ง์€, ํ”„๋กœ์ ํŠธ๋ช…/๋ชจ๋“ˆ๋ช…/src/test/java์˜ ๋””๋ ‰ํ† ๋ฆฌ์—์„œ๋งŒ ํ†ตํ•˜๋Š” ์ข…์†์„ฑ์ด๋ผ๋Š” ์ด์•ผ๊ธฐ๋‹ค. ํ”„๋กœ์ ํŠธ๋ฅผ APK๋กœ ๋งŒ๋“ค์–ด Play Store์— ์˜ฌ๋ฆด ๋•Œ ์ด testImplementation์€ (APK์˜ ์šฉ๋Ÿ‰ ๋‚ญ๋น„๋ฅผ ๋ง‰๊ธฐ ์œ„ํ•ด) ํฌํ•จ๋˜์ง€ ์•Š๋Š”๋‹ค. androidTestImplementation์€ Instrumented test์—๊ฒŒ๋งŒ ์ข…์†์„ฑ์„ ์ œ๊ณตํ•œ๋‹ค. ์ด ๋ง์€, ํ”„๋กœ์ ํŠธ๋ช…/๋ชจ๋“ˆ๋ช…/src/androidTest/java์˜ ๋””๋ ‰ํ† ๋ฆฌ์—์„œ๋งŒ ํ†ตํ•˜๋Š” ์ข…์†์„ฑ์ด๋ผ๋Š” ์ด์•ผ๊ธฐ๋‹ค. ํ”„๋กœ์ ํŠธ๋ฅผ APK๋กœ ๋งŒ๋“ค์–ด Play Store์— ์˜ฌ๋ฆด ๋•Œ ์ด androidTestImplementation์€ (APK์˜ ์šฉ๋Ÿ‰ ๋‚ญ๋น„๋ฅผ ๋ง‰๊ธฐ ์œ„ํ•ด) ํฌํ•จ๋˜์ง€ ์•Š๋Š”๋‹ค.
 

#3-2 Gradle ๋ฒ„์ „ ๋ฐ AGP ๋ฒ„์ „ ์„ค์ •

[File] - [Project Structure...]์—์„œ ํ”„๋กœ์ ํŠธ์˜ Gradle ๋ฒ„์ „ ๋ฐ AGP(Android Gradle Plugin) ๋ฒ„์ „์„ ๊ฐ๊ฐ 8.0 ๋ฐ 8.1.2๋กœ ์„ ํƒํ•œ๋‹ค.
 

#3-3 ํ”„๋กœ์ ํŠธ ์ˆ˜์ค€ build.gradle ์ค€๋น„

// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {
    id("com.android.application") version "8.1.2" apply false
    id("org.jetbrains.kotlin.android") version "1.9.0" apply false

    // KSP (Annotation ์ฝ๊ธฐ)
    id("com.google.devtools.ksp") version "1.9.0-1.0.13" apply false
}

 

#3-4 ๋ชจ๋“ˆ ์ˆ˜์ค€ build.gradle ์ค€๋น„

plugins {
    id("com.android.application")
    id("org.jetbrains.kotlin.android")

    // kapt, KSP (Annotation ์ฝ๊ธฐ)
    id("kotlin-kapt")
    id("com.google.devtools.ksp")
}

android {
    namespace = "com.example.setupenvironment"
    compileSdk = 34

    defaultConfig {
        applicationId = "com.example.setupenvironment"
        minSdk = 26
        targetSdk = 33
        versionCode = 1
        versionName = "1.0"

        testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        release {
            isMinifyEnabled = false
            proguardFiles(
                getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro"
            )
        }
    }
    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_17
        targetCompatibility = JavaVersion.VERSION_17
    }
    kotlinOptions {
        jvmTarget = "17"
    }
    buildFeatures {
        buildConfig = true // BuildConfig ํด๋ž˜์Šค๊ฐ€ ํ•„์š”ํ•  ์‹œ
        dataBinding = true // ๋ฐ์ดํ„ฐ ๋ฐ”์ธ๋”ฉ ์‹œ
    }
}

dependencies {

    // ํ”„๋กœ์ ํŠธ ์ƒ์„ฑ ์‹œ built-in ๋˜์–ด์žˆ๋˜ Dependency๋“ค (๋ฒ”์ฃผํ™”๋ฅผ ์œ„ํ•ด, ์ด ์ค‘ ์ผ๋ถ€๋Š” ์•„๋ž˜์ชฝ ์ฝ”๋“œ๋กœ ์˜ฎ๊ฒผ์Œ)
    implementation("androidx.core:core-ktx:1.9.0")
    implementation("androidx.appcompat:appcompat:1.7.0")
    implementation("com.google.android.material:material:1.12.0")
    implementation("androidx.constraintlayout:constraintlayout:2.1.4")
    androidTestImplementation("androidx.test.espresso:espresso-core:3.6.1") // Android์šฉ์œผ๋กœ ํŠน๋ณ„ํžˆ ๋งŒ๋“ค์–ด์ง„ ์‚ฌ์šฉ์ž ์ธํ„ฐํŽ˜์ด์Šค ํ…Œ์ŠคํŠธ ํ”„๋ ˆ์ž„์›Œํฌ

    // JUnit: ์ž๋ฐ”์™€ ์•ˆ๋“œ๋กœ์ด๋“œ ๊ฐœ๋ฐœ์—์„œ ํ‘œ์ค€์œผ๋กœ ์‚ฌ์šฉ๋˜๋Š” ํ…Œ์ŠคํŠธ ํ”„๋ ˆ์ž„์›Œํฌ. ๋‹ค๋ฅธ Dependency๋“ค์˜ ๊ธฐ๋ฐ˜์œผ๋กœ๋„ ๋„๋ฆฌ ์“ฐ์ธ๋‹ค
    testImplementation("junit:junit:4.13.2") // ํ”„๋กœ์ ํŠธ ์ƒ์„ฑ ์‹œ built-in ๋˜์–ด์žˆ๋˜ Dependency.
    androidTestImplementation("androidx.test.ext:junit:1.2.1") // ํ”„๋กœ์ ํŠธ ์ƒ์„ฑ ์‹œ built-in ๋˜์–ด์žˆ๋˜ Dependency. JUnit์„ ํ™•์žฅํ•ด ์•ˆ๋“œ๋กœ์ด๋“œ์—์„œ ํ…Œ์ŠคํŠธํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์คŒ
    testImplementation("androidx.test.ext:junit:1.2.1") // JUnit์„ ํ™•์žฅํ•ด ์•ˆ๋“œ๋กœ์ด๋“œ์—์„œ ํ…Œ์ŠคํŠธํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์คŒ (Local unit test์šฉ)

    // Lifecycle
    val lifecycleVersion = "2.8.3"
    testImplementation("androidx.lifecycle:lifecycle-runtime-testing:$lifecycleVersion") // Test์šฉ LifecycleOwner ๋“ฑ ์ œ๊ณต

    // LiveData
    val archVersion = "2.2.0"
    implementation("androidx.lifecycle:lifecycle-livedata-ktx:$lifecycleVersion")
    testImplementation("androidx.arch.core:core-testing:$archVersion") // Test helpers for LiveData (ํ…Œ์ŠคํŠธ์— LiveData๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ)
    androidTestImplementation("androidx.arch.core:core-testing:$archVersion") // Test helpers for LiveData (ํ…Œ์ŠคํŠธ์— LiveData๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ) (Instrumented test์šฉ)

    // ViewModel
    implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycleVersion")
    implementation("androidx.lifecycle:lifecycle-viewmodel-savedstate:$lifecycleVersion") // ViewModel์˜ ์ƒํƒœ ๊ด€๋ฆฌ๋ฅผ ๋•๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ

    // Coroutines
    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1")
    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4")

    // Dagger
    val daggerVersion = "2.51.1"
    implementation("com.google.dagger:dagger:$daggerVersion")
    kapt("com.google.dagger:dagger-compiler:$daggerVersion") // Dagger์˜ Annotation ๊ตฌ๋ฌธ์„ ์ฝ๊ธฐ ์œ„ํ•œ ์ข…์†์„ฑ

    // Retrofit
    val retrofitVersion = "2.11.0"
    val okhttp3Version = "4.12.0"
    implementation("com.squareup.retrofit2:retrofit:$retrofitVersion")
    implementation("com.squareup.retrofit2:converter-gson:$retrofitVersion") // JSON ์ปจ๋ฒ„ํ„ฐ
    implementation("com.squareup.okhttp3:logging-interceptor:$okhttp3Version") // ์›น ํ†ต์‹  ๋กœ๊ทธ
    testImplementation("com.squareup.okhttp3:mockwebserver:$okhttp3Version") // ์›น ์„œ๋ฒ„ Mock ์ƒ์„ฑ

    // Room
    val roomVersion = "2.6.1"
    implementation("androidx.room:room-runtime:$roomVersion")
    kapt("androidx.room:room-compiler:$roomVersion") // Room์˜ Annotation ๊ตฌ๋ฌธ์„ ์ฝ๊ธฐ ์œ„ํ•œ ์ข…์†์„ฑ
    implementation("androidx.room:room-ktx:$roomVersion") // Room์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” Coroutines ํด๋ž˜์Šค ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ

    // Truth: ํ…Œ์ŠคํŠธ ์„ฑ๊ณต ๋ฐ ์‹คํŒจ ๋ฉ”์‹œ์ง€๋ฅผ ๋” ์ฝ๊ธฐ ์‰ฝ๊ฒŒ ๋งŒ๋“ค์–ด์ฃผ๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ
    val truthVersion = "1.4.3"
    testImplementation("com.google.truth:truth:$truthVersion")
    testImplementation("com.google.truth.extensions:truth-java8-extension:$truthVersion") // Truth๊ฐ€ Java 8์— ๋„์ž…๋œ ๊ธฐ๋Šฅ์„ ์ด์šฉํ•ด ํ…Œ์ŠคํŠธํ•˜๋„๋ก ๋งŒ๋“ค์–ด์ฃผ๋Š” ์ถ”๊ฐ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ

    androidTestImplementation("com.google.truth:truth:$truthVersion")
    androidTestImplementation("com.google.truth.extensions:truth-java8-extension:$truthVersion") // Truth๊ฐ€ Java 8์— ๋„์ž…๋œ ๊ธฐ๋Šฅ์„ ์ด์šฉํ•ด ํ…Œ์ŠคํŠธํ•˜๋„๋ก ๋งŒ๋“ค์–ด์ฃผ๋Š” ์ถ”๊ฐ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ (Instrumented test์šฉ)

    // (JUnit์— ๊ธฐ๋ฐ˜) Mockito: Test double์˜ ์ผ์ข…์ธ Mock ์ƒ์„ฑ์„ ๋„์™€์ฃผ๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ
    testImplementation("org.mockito:mockito-core:5.12.0")
    testImplementation("org.mockito.kotlin:mockito-kotlin:5.3.1") // ์ข€ ๋” 'Kotlin์Šค๋Ÿฌ์šด' ๋ฐฉ์‹์œผ๋กœ Mock ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋„์™€์ฃผ๋Š” ์ถ”๊ฐ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ

    // (JUnit์— ๊ธฐ๋ฐ˜) Robolectric: ์•ˆ๋“œ๋กœ์ด๋“œ ์—๋ฎฌ๋ ˆ์ดํ„ฐ๋ฅผ ๋ชจ๋ฐฉํ•ด ๋น ๋ฅด๊ฒŒ ์•ˆ๋“œ๋กœ์ด๋“œ ํ™˜๊ฒฝ์„ ์‹œ๋ฎฌ๋ ˆ์ด์…˜. ์ฆ‰, ์›๋ž˜๋ผ๋ฉด Instrumented test๋ฅผ ์ง„ํ–‰ํ•ด์•ผ๋˜๋Š” ๊ฑธ Local unit test๋กœ ์ง„ํ–‰ํ•˜๊ฒŒ ๋งŒ๋“ค์–ด์คŒ
    testImplementation("org.robolectric:robolectric:4.12.2")

    // (JUnit์— ๊ธฐ๋ฐ˜) Glide: ์ด๋ฏธ์ง€ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ ๋ฐ ๊ด€๋ฆฌ
    implementation("com.github.bumptech.glide:glide:4.16.0")
}

#5์— ์žˆ๋Š” ์ด์–ด์ง€๋Š” ๊ธ€๋“ค์—์„œ ์‚ฌ์šฉํ•  ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋ฐ ํ…Œ์ŠคํŠธ์šฉ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋“ค์„ ์ „๋ถ€ ํฌํ•จํ–ˆ๋‹ค. testImplementation( ... )์— ๋น„ํ•ด androidTestImplementation( ... )์˜ ๊ฐฏ์ˆ˜๊ฐ€ ์ ์€ ๊ฒƒ์€ androidTestImplementation( ... )์˜ ํŠน์„ฑ์— ๊ธฐ์ธํ•œ๋‹ค. ๋ฐ”๋กœ, ํ…Œ์ŠคํŠธ ์‹œ์— ์•ˆ๋“œ๋กœ์ด๋“œ ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค๋Š” ์  ๋ง์ด๋‹ค. ๋•๋ถ„์— ํ”„๋กœ์ ํŠธ ์ „์—ญ์— Dependency๋ฅผ ์ œ๊ณตํ•˜๋Š” implementation( ... )๋งŒ์œผ๋กœ ์ข…์†์„ฑ์ด ์ถฉ์กฑ๋œ ๊ฒƒ์ด๋‹ค. ๋˜, compileOptions ๋ฐ kotlinOptions์˜ JDK ๋ฒ„์ „์ด 17์ž„์— ์œ ์˜ํ•˜์ž.
 
๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋งํฌ ๋ชจ์Œ

๋”๋ณด๊ธฐ

JUnit4

 

JUnit – About

JUnit is a simple framework to write repeatable tests. It is an instance of the xUnit architecture for unit testing frameworks. @Test public void newArrayListsHaveNoElements() { assertThat(new ArrayList ().size(), is(0)); } @Test public void sizeReturnsNum

junit.org

 

Truth

 

Truth - Fluent assertions for Java and Android

What is Truth? Truth is a library for performing assertions in tests: assertThat(notificationText).contains("testuser@google.com"); Truth is owned and maintained by the Guava team. It is used in the majority of the tests in Google’s own codebase. Why use

truth.dev

 

Mockito

 

Mockito framework site

Intro Why How More Who Links Training Why drink it? Mockito is a mocking framework that tastes really good. It lets you write beautiful tests with a clean & simple API. Mockito doesn’t give you hangover because the tests are very readable and they produc

site.mockito.org

 

Robolectric

 

Robolectric

test-drive your Android code Running tests on an Android emulator or device is slow! Building, deploying, and launching the app often takes a minute or more. That's no way to do TDD. There must be a better way. Robolectric is a framework that brings fast a

robolectric.org

 

Glide

 

Glide v4 : Fast and efficient image loading for Android

About Glide Glide is a fast and efficient image loading library for Android focused on smooth scrolling. Glide offers an easy to use API, a performant and extensible resource decoding pipeline and automatic resource pooling. Glide supports fetching, decodi

bumptech.github.io

 

#3-5 Gradle์ด ์‚ฌ์šฉํ•  JDK ๋ฒ„์ „ ์ง€์ •

[File] - [Setting...] - [Build, Execution, Deployment] - [Build Tools] - [Gradle]์—์„œ Gradle์ด ์‚ฌ์šฉํ•  JDK๋ฅผ ์ง€์ •ํ•œ๋‹ค. General settings์—์„œ๋Š” JDK 17์˜ ๋””๋ ‰ํ† ๋ฆฌ๋ฅผ ์ง€์ •ํ•œ๋‹ค. Gradle projects์—์„œ๋Š” Gradle JDK๋ฅผ ์„ค์ •ํ•œ๋‹ค. ์ด ๋•Œ ์ด ๊ฒŒ์‹œ๊ธ€์„ ์ฐธ์กฐํ•ด JDK 17 ์„ค์น˜ ๋ฐ ํ™˜๊ฒฝ ๋ณ€์ˆ˜ JAVA_HOME์„ ์„ค์ •ํ•˜๊ณ  JAVA_HOME์„ ์„ ํƒํ•˜๊ฑฐ๋‚˜, ์ด๋ฏธ ์„ค์น˜๋œ 17๋ฒ„์ „์˜ JDK ๋””๋ ‰ํ† ๋ฆฌ๋ฅผ ์„ ํƒํ•œ๋‹ค. ํ›„์ž์˜ ๋ฐฉ๋ฒ•์ด ๋” ๊ฐ„ํŽธํ•˜๋‹ค. ๋งŒ์•ฝ ๋ชฉ๋ก์— '์ด๋ฏธ ์„ค์น˜๋œ 17๋ฒ„์ „์˜ JDK ๋””๋ ‰ํ† ๋ฆฌ'๊ฐ€ ๋ณด์ด์ง€ ์•Š๋Š”๋‹ค๋ฉด, [Download JDK...]๋ฅผ ๋ˆŒ๋Ÿฌ ๋‹ค์šด๋กœ๋“œํ•˜๋ฉด ๋œ๋‹ค.
 

#4 ์š”์•ฝ

Unit Test๋ฅผ ํ†ตํ•ด AVD๋กœ ์ผ์ผํžˆ ํ™•์ธํ•˜๋Š” ์‹œ๊ฐ„ ๋‚ญ๋น„๋ฅผ ์ค„์ธ๋‹ค.

#5 ์ด์–ด์ง€๋Š” ๊ธ€

#5-1 Android unit test์˜ ๊ธฐ์ดˆ 

 

[Android] Unit Testing - ๊ธฐ์ดˆ

#1 ์ด์ „ ๊ธ€#1-1 Unit Testing ๊ฐœ์š” [Android] Unit Testing - ๊ฐœ์š”์™€ ํ™˜๊ฒฝ ์„ค์ •#1 ์•ˆ๋“œ๋กœ์ด๋“œ ์•ฑ ํ…Œ์ŠคํŠธ#1-1 ์•ˆ๋“œ๋กœ์ด๋“œ ์•ฑ ํ…Œ์ŠคํŠธ์˜ ์ข…๋ฅ˜๋จผ์ €, ์—ฌ๊ธฐ์— ์žˆ๋Š” ๊ตฌ๊ธ€ ๊ณต์‹ ๋ฌธ์„œ์—์„œ ์•ˆ๋“œ๋กœ์ด๋“œ ์•ฑ ํ…Œ์ŠคํŠธ์— ๋Œ€ํ•œ

kenel.tistory.com

 

#5-2 ViewModel ํ…Œ์ŠคํŠธ 

 

[Android] Unit Testing - ViewModel

#1 ์ด์ „ ๊ธ€#1-1 Unit Testing ๊ฐœ์š” [Android] Unit Testing - ๊ฐœ์š”์™€ ํ™˜๊ฒฝ ์„ค์ •#1 ์•ˆ๋“œ๋กœ์ด๋“œ ์•ฑ ํ…Œ์ŠคํŠธ#1-1 ์•ˆ๋“œ๋กœ์ด๋“œ ์•ฑ ํ…Œ์ŠคํŠธ์˜ ์ข…๋ฅ˜๋จผ์ €, ์—ฌ๊ธฐ์— ์žˆ๋Š” ๊ตฌ๊ธ€ ๊ณต์‹ ๋ฌธ์„œ์—์„œ ์•ˆ๋“œ๋กœ์ด๋“œ ์•ฑ ํ…Œ์ŠคํŠธ์— ๋Œ€ํ•œ

kenel.tistory.com

 

#5-3 Room, LiveData ํ…Œ์ŠคํŠธ

 

[Android] Unit Testing - Room๊ณผ LiveData

#1 ์ด์ „ ๊ธ€#1-1 Unit Testing ๊ฐœ์š” [Android] Unit Testing - ๊ฐœ์š”์™€ ํ™˜๊ฒฝ ์„ค์ •#1 ์•ˆ๋“œ๋กœ์ด๋“œ ์•ฑ ํ…Œ์ŠคํŠธ#1-1 ์•ˆ๋“œ๋กœ์ด๋“œ ์•ฑ ํ…Œ์ŠคํŠธ์˜ ์ข…๋ฅ˜๋จผ์ €, ์—ฌ๊ธฐ์— ์žˆ๋Š” ๊ตฌ๊ธ€ ๊ณต์‹ ๋ฌธ์„œ์—์„œ ์•ˆ๋“œ๋กœ์ด๋“œ ์•ฑ ํ…Œ์ŠคํŠธ์— ๋Œ€ํ•œ

kenel.tistory.com

 

#5-4 Retrofit ํ…Œ์ŠคํŠธ

 

[Android] Unit Testing - Retrofit

#1 ์ด์ „ ๊ธ€#1-1 Unit Testing ๊ฐœ์š” [Android] Unit Testing - ๊ฐœ์š”์™€ ํ™˜๊ฒฝ ์„ค์ •#1 ์•ˆ๋“œ๋กœ์ด๋“œ ์•ฑ ํ…Œ์ŠคํŠธ#1-1 ์•ˆ๋“œ๋กœ์ด๋“œ ์•ฑ ํ…Œ์ŠคํŠธ์˜ ์ข…๋ฅ˜๋จผ์ €, ์—ฌ๊ธฐ์— ์žˆ๋Š” ๊ตฌ๊ธ€ ๊ณต์‹ ๋ฌธ์„œ์—์„œ ์•ˆ๋“œ๋กœ์ด๋“œ ์•ฑ ํ…Œ์ŠคํŠธ์— ๋Œ€ํ•œ

kenel.tistory.com