Skip to main content

🎯 Assertion

πŸ“– What is an Assertion?​

Assertion is verifying the expected results in tests. With Kotest, you can perform more readable and powerful validations!

πŸ’‘ Kotest Setup​

build.gradle.kts​

dependencies {
testImplementation("io.kotest:kotest-runner-junit5:5.5.0")
testImplementation("io.kotest:kotest-assertions-core:5.5.0")
}

🎯 Basic Assertions​

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
}
})

Various Matchers​

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
}
})

🎨 Collection Assertions​

List Validation​

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 Validation​

class MapTest : StringSpec({
"Map 검증" {
val map = mapOf("name" to "홍길동", "age" to "25")

// ν‚€/κ°’ 쑴재
map shouldContainKey "name"
map shouldContainValue "홍길동"

// ν•­λͺ© 검증
map shouldContain ("name" to "홍길동")

// 크기
map shouldHaveSize 2
}
})

πŸ”₯ Practical Examples​

User Validation​

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+")
}
})

Order Validation​

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
}
})

πŸ›‘οΈ Exception Assertions​

Validating Exceptions​

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 Assertions​

Multiple Validations at Once​

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 // 이것도 체크
}
// λͺ¨λ“  μ‹€νŒ¨λ₯Ό ν•œλ²ˆμ— λ³΄μ—¬μ€Œ
}
})

πŸ”§ Custom Matchers​

Your Own Validation​

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 Comparison​

Partial Comparison​

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
}
})

πŸ”₯ Practical Patterns​

Range Validation​

class RangeTest : StringSpec({
"λ²”μœ„ 검증" {
val score = 85

score shouldBeInRange 0..100
score shouldBeGreaterThan 60
score shouldBeLessThan 90
}

"λ‚ μ§œ λ²”μœ„" {
val today = "2024-12-25"

today shouldBeGreaterThan "2024-01-01"
today shouldBeLessThan "2025-01-01"
}
})

Type Validation​

import io.kotest.matchers.types.*

class TypeTest : StringSpec({
"νƒ€μž… 검증" {
val value: Any = "hello"

value.shouldBeInstanceOf<String>()
value shouldBe instanceOf<String>()
}

"Null 검증" {
val nullValue: String? = null
val nonNull: String? = "test"

nullValue.shouldBeNull()
nonNull.shouldNotBeNull()
}
})

Regex Validation​

class RegexTest : StringSpec({
"μ •κ·œμ‹ λ§€μΉ­" {
val email = "hong@example.com"

email shouldMatch Regex("\\w+@\\w+\\.\\w+")
}

"μ „ν™”λ²ˆν˜Έ 검증" {
val phone = "010-1234-5678"

phone shouldMatch Regex("\\d{3}-\\d{4}-\\d{4}")
}
})

πŸ€” Frequently Asked Questions​

Q1. shouldBe vs assertEquals?​

A: shouldBe is more readable!

// JUnit
assertEquals(5, result)

// Kotest
result shouldBe 5 // 더 μžμ—°μŠ€λŸ¬μ›€

Q2. Customizing failure messages?​

A: Use withClue!

import io.kotest.assertions.withClue

class ClueTest : StringSpec({
"μ»€μŠ€ν…€ λ©”μ‹œμ§€" {
withClue("μ‚¬μš©μž λ‚˜μ΄ 검증 μ‹€νŒ¨") {
25 shouldBeInRange 20..30
}
}
})

Q3. Only one of multiple conditions?​

A: Use anyOf!

import io.kotest.matchers.or

class AnyOfTest : StringSpec({
"μ—¬λŸ¬ 쑰건 쀑 ν•˜λ‚˜" {
val value = 5

value shouldBe (3 or 5 or 7)
}
})

🎬 Conclusion​

Reliable validation with powerful assertions!

Key Takeaways:
βœ… Concise validation with shouldBe
βœ… Utilize various matchers
βœ… All at once with Soft Assertions
βœ… Write custom matchers
βœ… Type/Range/Regex validation

Next Step: Learn about test doubles in Mocking!