Kotest

๊ธฐ๋ฅ์ ๊ตฌํํ๋ ์ฝ๋ ์์ฑ
๊ทธ ๊ธฐ๋ฅ์ด ์ ์์ ์ผ๋ก ์๋ํ๋์ง AVD๋ ๋๋ฐ์ด์ค์์ ๋น๋ํ์ฌ ๊ธฐ๋ฅ ํ์ธ
์๋ฌ๊ฐ ๋ฐ์ํ๋ฉด ์ฝ๋ ์์ ํ ๋ค์ ๋น๋ํ์ฌ ํ์ธ
์์ ๊ฐ์ ์์๋ฅผ ๋ฐ๋ณตํ๊ฒ ๋๋๋ฐ ํ๋ก์ ํธ ๊ท๋ชจ๊ฐ ์๋ค๋ฉด ์์ ๊ฐ์ ์์๋ก ๋ฐ๋ณตํด๋ ๊ทธ๋ ๊ฒ ํฌ๊ฒ ์ฐจ์ด๊ฐ ๋์ง ์๋๋ค.. ๊ทธ๋ฌ๋ But ํ๋ก์ ํธ์ ๊ท๋ชจ๊ฐ ์ปค์ง๋ค๋ฉด??!! ์ฑ์ ๋น๋ํ๋ ์๊ฐ + UI์ ์ ๋ ฅํ์ฌ ํ ์คํธํ๋ ์๊ฐ์ด ๋ํด์ ธ ๋ง์ ์๊ฐ์ ํ์๋ก ํ ๊ฒ์ด๋ค.
ํ์ฌ ํ์ฌ์์๋ง ํด๋ ์ฑ ๋น๋ ํ๋ ๋ฐ๋ง 2~3๋ถ์ด ์์๋๊ณ ๋ ์ถ๊ฐํ ๊ธฐ๋ฅ์ ํ ์คํธํ๋๋ฐ ์ถ๊ฐ์ ์ธ ์๊ฐ์ด ํ์ํ๋ค.
ํ ์คํธ ์ฝ๋๋ฅผ ์์ฑํจ์ผ๋ก์จ ์ป๋ ์ด์ ์ ์ดํด๋ณด๋ฉด
์๋ชป๋ ๋ถ๋ถ์ ๋น ๋ฅด๊ฒ ํ์ธ ๊ฐ๋ฅ
๋๋ฒ๊น ์๊ฐ ๋จ์ถ
๋ชจ๋์ด ์๋ํ๋๋ก ๋์ํ๊ณ ์๋์ง ํ์ธ ๊ฐ๋ฅ
ํด๋ฆฐํ ๊ตฌ์กฐ์ ๊ฐ๋ฐ ๊ฐ๋ฅ
์์ ๊ฐ์ ์ฅ์ ์ด ๋ง๊ธฐ ๋๋ฌธ์ ์ฐ๋ฆฌ๋ ๊ธฐ๋ฅ์ ํ ์คํธํ ๋ ํ ์คํธ ์ฝ๋๋ฅผ ์์ฑํ๋๋ก ํด์ผ ํ๋ค.
์ฐ์ ์์์ผ ํ ๊ฒ ์๋๋ก์ด๋๋ ๋๋ฐ์ด์ค ์์กด๋๊ฐ ๊ฐํ ํ๋ ์์ํฌ๋ผ ์๋๋ก์ด๋ OS๊ฐ ์ค์น๋ ๋๋ฐ์ด์ค์์๋ง ๋์ํ๋ค. ๊ทธ๋ ๊ธฐ ๋๋ฌธ์ JVM์ด ์คํํ๋ ์๋๋ก์ด๋ Unit Test์์ ์๋๋ก์ด๋์ ์ปดํฌ๋ํธ๋ค์ ๊ทธ๋๋ก ์ฌ์ฉํ๊ฑฐ๋ ๊ฐ์ฒด๋ฅผ ๋ง๋ค ๋ ๋ฌธ์ ๊ฐ ๋ฐ์ํ๋ค. (Mocking ๊ฐ์ ๋ฐฉ๋ฒ์ ์ฌ์ฉํ์ฌ ๊ฐ์ง ๊ฐ์ฒด๋ฅผ ๋ง๋ค์ด ํ ์คํธ)
์ด์ ๊ฐ์ ์ด์ ๋ก ์ต๋ํ ์๋๋ก์ด๋ ํ๋ ์์ํฌ์ ์์กด์ฑ์ด ์๋ ์ฝ๋๋ก ๋ถ๋ฆฌํ๋ ๊ฒ์ด ์ข๋ค.(DI, MVVM, Clean Architecture๋ฑ)
์๋๋ก์ด๋์๋ ๋ก์ปฌ ๋จ์ ํ ์คํธ(Unit Test)์ ๊ณ์ธก ํ ์คํธ(Instrumentation Test) ์ด ๋ ๊ฐ์ง ํ ์คํธ๊ฐ ์๋ค.
๋ก์ปฌ ๋จ์ ํ
์คํธ(Unit Test)
module-name/src/test/java/ ํ์์ ํ ์คํธ ์ฝ๋ ์์ฑ
ํ ์คํธ ์๋๊ฐ ๋น ๋ฅด๋ค
JVM์์ ์คํ๋๋ ํ ์คํธ
์๋๋ก์ด๋ ํ๋ ์์ํฌ์ ์ข ์์ฑ์ด ์๊ฑฐ๋ ๋ชจ์ ๊ฐ์ฒด๋ฅผ ์์ฑํ ์ ์๋ ๊ฒฝ์ฐ ์ด ํ ์คํธ ์ฌ์ฉ
JUnit, Mockito, PowerMock, Truth, Robolectric, Kotest
๊ณ์ธก ํ
์คํธ(Instrumentation Test)
module-name/src/androidTest/java/ ํ์์ ํ ์คํธ ์ฝ๋ ์์ฑ
์๋๋ก์ด๋ ํ๋ ์์ํฌ์ ์ข ์์ฑ์ด ์๋ ํ ์คํธ
์ค์ ์๋๋ก์ด๋ ๊ธฐ๊ธฐ๋ ์๋ฎฌ๋ ์ดํฐ์์ ์คํ๋๋ ํ ์คํธ
Espresso, UIAnimator, Robotium, Appium, Calabash
์ด ์ค์์ ์ฝํ๋ฆฐ์ ์ฌ์ฉํ์ฌ Unit Test๋ฅผ ํ ์ ์๋ Kotest๋ผ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํด ๋ณด๋ ค ํ๋ค.
Kotest
Kotest๋ Kotlin์ ์ฌ์ฉํ์ฌ Unit Test๋ฅผ ํ ์ ์๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ด๋ค.
์ฌ์ฉ ๋ฐฉ๋ฒ์ผ๋ก๋ ์ฐ์
1. ์์กด์ฑ ์ถ๊ฐ
android.testOptions {
unitTests.all {
useJUnitPlatform()
}
}
testImplementation 'io.kotest:kotest-runner-junit5:5.0.3'
App๋จ์ Gradle์ ์์ ๊ฐ์ ์์กด์ฑ์ ์ถ๊ฐํฉ๋๋ค.
2. ํ ์คํธ ์ฝ๋ ์์ฑ ์์น
ํ ์คํธ ์ฝ๋๋ฅผ ์์ฑํ๊ธฐ ์ํด ํ๋ก์ ํธ๋ฅผ ํ๋ ์๋ก ๋ง๋ค์๋๋ฐ ์์ ExampleUnitTest ์์น์ ํ ์คํธํ ์ฝํ๋ฆฐ ํ์ผ์ ๋ง๋ค์ด์ฃผ๋ฉด ๋๋ค.
3. ํ ์คํธ ์ฝ๋ ์์ฑ
์ฐ์ Kotest์์๋ Spec์ด๋ผ๋ ์ด๋ฆ์ผ๋ก ์ฌ๋ฌ ํ ์คํธ ์คํ์ผ์ ์ง์ํฉ๋๋ค. ์ด ์ค์ ๊ฐ์ฅ ๊ฐ๋จํ๊ฑด StringSpec ์ ๋๋ค. ์๋์ ๊ฐ์ด ์์ฑํ๋๋ฐ ํ ์คํธ ์ฝ๋๋ init ์์ ์์ฑํ๊ณ ๊ทธ ์์ ์ฝ๋์ Description, ํ ์คํธํ ์ฝ๋์์ผ๋ก ์์ฑํฉ๋๋ค.
StringSpec
class StringTest: StringSpec() { // StringSpec์ ์์
init { // ํ
์คํธ ์ฝ๋ ์์ฑ
"strings.length should return size of string" { // ์ฝ๋ ์ค๋ช
- ํ
์คํธ์ ๊ด์ฌx
"hello".length shouldBe 5 // hello ๋ฌธ์์ด์ ๊ธธ์ด๊ฐ 5์ธ์ง ์ฒดํฌ
}
}
}
Kotest์๋ StringSpec ๋ง๊ณ ๋ ์ฌ๋ฌ ์คํ์ด ์๋๋ฐ ์ฝ๋ ๋ฐฉ์๋ง ๋ค๋ฅผ ๋ฟ ์์ฑํ๋ ํ ์คํธ ์ฝ๋๋ ๋์ผํฉ๋๋ค. ์ด ๋ถ๋ถ์ ๋ํด์ ์ทจํฅ
๋ช ๊ฐ์ง ๋ ์์ ๋ฅผ ๋ณด๋ฉด
FunSpec
class FunSpecTest: FunSpec() { // ํจ์ ํํ๋ก ํ
์คํธ ์ฝ๋๋ฅผ ์์ฑํ๋ค.
init {
test("String length should return length of the string") { // ํ
์คํธ ์ฝ๋ ์ค๋ช
- description
"sanggun".length shouldBe 7 // ๋ฌธ์์ด์ ๊ธธ์ด๋ฅผ ์ฒดํฌํ๋ ์ฝ๋
"hello".length shouldBe 5
}
}
}
AnnotationSpec
class AnnotationTest : AnnotationSpec() { // ์ด๋
ธํ
์ด์
ํํ๋ก ์์ฑ, JUnit๊ณผ ๋น์ทํ๋ค.
@BeforeEach
fun beforeTest() {
println("Before each test")
}
@Test
fun test1() {
1 shouldBe 1
}
@Test
fun test2() {
3 shouldBe 3
}
}
๋ฑ๋ฑ ๋ง์ Spec ์ด ์์ต๋๋ค. ์์ธํ๊ฑด ์ฌ๊ธฐ๐
๋ค์์ Matcher์ ๋๋ค. Matcher๋ ํ ์คํธ ์ฝ๋๋ฅผ ์์ฑํ๋๋ฐ ๋์์ฃผ๋ ์์๋ค์ ๋๋ค. ์๋ฅผ๋ค์ด, ์๋ ์ฝ๋์์ shouldBe๋ ๋์ผํจ์ ์ฒดํฌํด์ฃผ๋ Matcher์ ๋๋ค.
"sanggun".length shouldBe 7
Matcher๋ ์ฌ๋ฌ ๊ฐ์ง๊ฐ ์๋๋ฐ
class MatcherTest : StringSpec() {
init {
-----------------------String Matchers-------------------------
// 'shouldBe'๋ ๋์ผํจ์ ์ฒดํฌํ๋ Matcher
"hello world" shouldBe haveLength(11) // length๊ฐ 11์ด์ด์ผ ํจ์ ์ฒดํฌ
"hello" should include("ll") // ํ๋ผ๋ฏธํฐ๊ฐ ํฌํจ๋์ด ์๋์ง ์ฒดํฌ
"hello" should endWith("lo") // ํ๋ผ๋ฏธํฐ๊ฐ ๋์ ํฌํจ๋๋์ง ์ฒดํฌ
"hello" should match("he...") // ํ๋ผ๋ฏธํฐ๊ฐ ๋งค์นญ๋๋์ง ์ฒดํฌ
"hello".shouldBeLowerCase() // ์๋ฌธ์๋ก ์์ฑ๋์๋์ง ์ฒดํฌ
-----------------------Collection Matchers-------------------------
val list = emptyList<String>()
val list2 = listOf("a", "b", "c")
val map = mapOf<String, String>(Pair("a", "1"))
list should beEmpty() // ์์๊ฐ ๋น์๋์ง ์ฒดํฌ ํฉ๋๋ค.
list2 shouldBe sorted<String>() // ํด๋น ์๋ฃํ์ด ์ ๋ ฌ ๋์๋์ง ์ฒดํฌ
map should contain("a", "1") // ํด๋น ์์๊ฐ ํฌํจ๋์๋์ง ์ฒดํฌ
map should haveKey("a") // ํด๋น key๊ฐ ํฌํจ๋์๋์ง ์ฒดํฌ
map should haveValue("1") // ํด๋น value๊ฐ ํฌํจ๋์๋์ง ์ฒดํฌ
}
}
์์ ๊ฐ์ด ๋ง์ Matcher๋ค์ด ์กด์ฌํฉ๋๋ค.
Last updated