Step 10 of 13
kotlin.test assertions, test lifecycle, MockK mocking library, test naming conventions
เขียนเทสด้วย kotlin.test — assertions, test lifecycle, และ MockK สำหรับ mocking
Add the test dependency in your build.gradle.kts:
dependencies {
testImplementation(kotlin("test"))
}
This gives you kotlin.test — a multiplatform testing framework. On the JVM, it runs on JUnit 5 by default.
Create src/test/kotlin/CalculatorTest.kt:
import kotlin.test.Test
import kotlin.test.assertEquals
class CalculatorTest {
@Test
fun addTwoPositiveNumbers() {
val result = add(2, 3)
assertEquals(5, result)
}
@Test
fun addNegativeNumbers() {
val result = add(-1, -2)
assertEquals(-3, result)
}
}
fun add(a: Int, b: Int): Int = a + b
Run tests from IntelliJ or the command line:
./gradlew test
import kotlin.test.*
class AssertionExamples {
@Test
fun equalityChecks() {
assertEquals(5, 2 + 3) // expected, actual
assertNotEquals(6, 2 + 3)
}
@Test
fun booleanChecks() {
assertTrue(5 > 3)
assertFalse(3 > 5)
}
@Test
fun nullChecks() {
val name: String? = null
assertNull(name)
val email: String? = "alice@email.com"
assertNotNull(email)
}
@Test
fun exceptionChecks() {
assertFailsWith<IllegalArgumentException> {
requireAge(-5)
}
}
}
fun requireAge(age: Int): Int {
require(age >= 0) { "Age cannot be negative" }
return age
}
import kotlin.test.*
data class Stack<T>(private val items: MutableList<T> = mutableListOf()) {
fun push(item: T) = items.add(item)
fun pop(): T = items.removeAt(items.lastIndex)
fun peek(): T = items.last()
val size: Int get() = items.size
}
class StackTest {
@Test
fun pushAddsItem() {
val stack = Stack<Int>()
stack.push(42)
assertEquals(1, stack.size)
assertEquals(42, stack.peek())
}
@Test
fun popRemovesAndReturnsLastItem() {
val stack = Stack<String>()
stack.push("A")
stack.push("B")
val popped = stack.pop()
assertEquals("B", popped)
assertEquals(1, stack.size)
}
}
import kotlin.test.*
class LifecycleTest {
@BeforeTest
fun setup() {
println("Runs before EACH test")
}
@AfterTest
fun teardown() {
println("Runs after EACH test")
}
@Test
fun firstTest() { println("Test 1") }
@Test
fun secondTest() { println("Test 2") }
}
Add MockK for tests that need to replace external dependencies:
// build.gradle.kts
dependencies {
testImplementation("io.mockk:mockk:1.13.16")
}
Mock a database or API so you can test logic without real I/O:
import io.mockk.every
import io.mockk.mockk
import io.mockk.verify
import kotlin.test.*
interface UserRepository {
fun findById(id: String): User?
fun save(user: User): User
}
data class User(val id: String, val name: String)
class UserService(private val repo: UserRepository) {
fun getUserName(id: String): String {
return repo.findById(id)?.name ?: "Unknown"
}
}
class UserServiceTest {
@Test
fun returnsUserNameWhenUserExists() {
// Arrange: create a mock repository
val mockRepo = mockk<UserRepository>()
every { mockRepo.findById("123") } returns User("123", "Alice")
val service = UserService(mockRepo)
// Act
val name = service.getUserName("123")
// Assert
assertEquals("Alice", name)
verify { mockRepo.findById("123") }
}
@Test
fun returnsUnknownWhenUserMissing() {
val mockRepo = mockk<UserRepository>()
every { mockRepo.findById(any()) } returns null
val service = UserService(mockRepo)
assertEquals("Unknown", service.getUserName("999"))
}
}
Use descriptive names that describe the scenario and expected outcome:
@Test
fun `pop on empty stack throws exception`() { }
@Test
fun `push then pop returns last pushed item`() { }
Write tests for a TemperatureConverter:
import kotlin.test.*
object TemperatureConverter {
fun celsiusToFahrenheit(celsius: Double): Double = celsius * 9 / 5 + 32
fun fahrenheitToCelsius(fahrenheit: Double): Double = (fahrenheit - 32) * 5 / 9
}
class TemperatureConverterTest {
@Test
fun `0C converts to 32F`() {
assertEquals(32.0, TemperatureConverter.celsiusToFahrenheit(0.0))
}
@Test
fun `100C converts to 212F`() {
assertEquals(212.0, TemperatureConverter.celsiusToFahrenheit(100.0))
}
@Test
fun `32F converts to 0C`() {
assertEquals(0.0, TemperatureConverter.fahrenheitToCelsius(32.0))
}
@Test
fun `round trip preserves value`() {
val original = 25.0
val converted = TemperatureConverter.fahrenheitToCelsius(
TemperatureConverter.celsiusToFahrenheit(original)
)
assertEquals(original, converted, 0.001)
}
}