🎯 Assertion
📖 什麼是Assertion?
Assertion是在測試中驗證預期結果。使用Kotest,您可以執行更易讀、更強大的驗證!
💡 Kotest配置
build.gradle.kts
dependencies {
testImplementation("io.kotest:kotest-runner-junit5:5.5.0")
testImplementation("io.kotest:kotest-assertions-core:5.5.0")
}
🎯 基本Assertion
shouldBe
import io.kotest.matchers.shouldBe
import io.kotest.core.spec.style.StringSpec
class BasicAssertionTest : StringSpec({
"숫자 비교" {
val result = 2 + 3
result shouldBe 5
}
"문자열 비교" {
val name = "Kotlin"
name shouldBe "Kotlin"
}
"불린 검증" {
val isValid = true
isValid shouldBe true
}
})
各種Matcher
import io.kotest.matchers.*
import io.kotest.matchers.string.*
class MatcherTest : StringSpec({
"다양한 비교" {
// 동등성
5 shouldBe 5
5 shouldNotBe 6
// 크기 비교
10 shouldBeGreaterThan 5
3 shouldBeLessThan 10
5 shouldBeInRange 1..10
// 문자열
"hello" shouldStartWith "he"
"world" shouldEndWith "ld"
"kotlin" shouldContain "otl"
"test" shouldHaveLength 4
}
})
🎨 集合Assertion
列表驗證
import io.kotest.matchers.collections.*
class CollectionTest : StringSpec({
"리스트 검증" {
val numbers = listOf(1, 2, 3, 4, 5)
// 크기
numbers shouldHaveSize 5
numbers.shouldNotBeEmpty()
// 포함
numbers shouldContain 3
numbers shouldContainAll listOf(1, 3, 5)
// 순서
numbers.shouldBeSorted()
// 조건
numbers.forAll { it shouldBeGreaterThan 0 }
numbers.forAtLeastOne { it shouldBe 3 }
}
})
Map驗證
class MapTest : StringSpec({
"Map 검증" {
val map = mapOf("name" to "홍길동", "age" to "25")
// 키/값 존재
map shouldContainKey "name"
map shouldContainValue "홍길동"
// 항목 검증
map shouldContain ("name" to "홍길동")
// 크기
map shouldHaveSize 2
}
})
🔥 實戰範例
用戶驗證
data class User(
val name: String,
val email: String,
val age: Int
)
class UserTest : StringSpec({
"사용자 정보 검증" {
val user = User("홍길동", "hong@example.com", 25)
user.name shouldBe "홍길동"
user.email shouldContain "@"
user.age shouldBeInRange 1..100
}
"이메일 형식 검증" {
val user = User("김철수", "kim@test.com", 30)
user.email shouldStartWith "kim"
user.email shouldEndWith ".com"
user.email shouldMatch Regex("\\w+@\\w+\\.\\w+")
}
})
訂單驗證
data class Order(
val id: String,
val items: List<Item>,
val total: Double
)
data class Item(val name: String, val price: Double)
class OrderTest : StringSpec({
"주문 검증" {
val order = Order(
id = "ORDER-001",
items = listOf(
Item("사과", 1000.0),
Item("바나나", 1500.0)
),
total = 2500.0
)
// ID 검증
order.id shouldStartWith "ORDER-"
// 아이템 검증
order.items shouldHaveSize 2
order.items.forAll { it.price shouldBeGreaterThan 0.0 }
// 합계 검증
order.total shouldBe 2500.0
}
})
🛡️ 異常Assertion
驗證異常
import io.kotest.assertions.throwables.*
class ExceptionTest : StringSpec({
"예외 발생 검증" {
shouldThrow<IllegalArgumentException> {
validateAge(-1)
}
}
"예외 메시지 검증" {
val exception = shouldThrow<IllegalArgumentException> {
validateAge(-1)
}
exception.message shouldBe "나이는 0 이상이어야 합니다"
}
"예외 발생 안함" {
shouldNotThrowAny {
validateAge(25)
}
}
})
fun validateAge(age: Int) {
require(age >= 0) { "나이는 0 이상이어야 합니다" }
}
🎯 Soft Assertion
一次多個驗證
import io.kotest.assertions.assertSoftly
class SoftAssertionTest : StringSpec({
"Soft Assertion" {
val user = User("홍길동", "hong@example.com", 25)
assertSoftly(user) {
name shouldBe "홍길동"
email shouldContain "@"
age shouldBeInRange 20..30
}
}
"모든 실패를 한번에 보기" {
assertSoftly {
1 shouldBe 2 // 실패해도 계속
"hello" shouldBe "world" // 이것도 체크
true shouldBe false // 이것도 체크
}
// 모든 실패를 한번에 보여줌
}
})
🔧 自定義Matcher
您自己的驗證
import io.kotest.matchers.Matcher
import io.kotest.matchers.MatcherResult
import io.kotest.matchers.should
fun beEven() = Matcher<Int> { value ->
MatcherResult(
value % 2 == 0,
{ "$value는 짝수여야 합니다" },
{ "$value는 짝수가 아니어야 합니다" }
)
}
fun bePositive() = Matcher<Int> { value ->
MatcherResult(
value > 0,
{ "$value는 양수여야 합니다" },
{ "$value는 양수가 아니어야 합니다" }
)
}
class CustomMatcherTest : StringSpec({
"커스텀 Matcher" {
4 should beEven()
10 should bePositive()
}
})
🎨 資料類別比較
部分比較
data class Person(
val name: String,
val age: Int,
val address: String
)
class PersonTest : StringSpec({
"데이터 클래스 비교" {
val person = Person("홍길동", 25, "서울")
// 전체 비교
person shouldBe Person("홍길동", 25, "서울")
// 부분 비교
person.name shouldBe "홍길동"
person.age shouldBeInRange 20..30
}
})