Kotlin 测试:单元测试、集成测试、端到端测试——完整指南

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

Kotlin 测试入门:从单元测试到端到端测试

测试是开发可靠软件不可或缺的一部分。在 Kotlin 生态系统中(该生态系统广泛用于 Android 开发、基于 Ktor 的后端以及多平台项目),有一套强大的工具包支持所有测试级别。本文将详细解析三个关键级别:单元测试、集成测试和端到端(e2e)测试。您将了解它们的区别、适用场景,以及如何通过代码示例在 Kotlin 中编写有效的测试。



Kotlin 单元测试:可靠性的基石

单元测试用于独立验证单个组件(函数、类)的运行情况。在 Kotlin 中,事实标准是使用 JUnit 5 框架,配合模拟库 MockK。



使用 JUnit 5 和 MockK 的单元测试示例

考虑一个简单的折扣计算服务:

class DiscountService(private val userRepository: UserRepository) {    fun calculateDiscount(userId: String, amount: Double): Double {        val user = userRepository.findById(userId) ?: return amount        return if (user.isPremium) amount * 0.9 else amount    }}

针对该服务的测试:

import io.mockk.everyimport io.mockk.mockkimport org.junit.jupiter.api.Testimport kotlin.test.assertEquals

class DiscountServiceTest {

@Test fun `should apply 10% discount for premium user`() { // Arrange val userRepo = mockk<UserRepository>() every { userRepo.findById("123") } returns User("123", isPremium = true) val service = DiscountService(userRepo)

// Act val result = service.calculateDiscount("123", 100.0)

// Assert assertEquals(90.0, result) }

@Test fun `should not apply discount for regular user`() { val userRepo = mockk<UserRepository>() every { userRepo.findById("456") } returns User("456", isPremium = false) val service = DiscountService(userRepo)

val result = service.calculateDiscount("456", 100.0)

assertEquals(100.0, result) }}

关键要点:

  • 使用 mockk{} 创建模拟对象。
  • 使用 every { ... } returns ... 块定义模拟行为。
  • 采用 Arrange-Act-Assert(准备-执行-断言)结构,使测试更易读。
  • 单元测试应快速运行,且不依赖外部资源。


集成测试:验证组件交互

集成测试用于验证多个模块协同工作的情况——例如,服务与真实数据库或外部 API 的交互。在 Kotlin 中,常用 Testcontainers(用于 Docker 容器)和 Spring Boot Test(用于后端)。



使用 Testcontainers 和 Ktor 的集成测试示例

假设我们有一个使用 PostgreSQL 的 Ktor 应用:

class UserRepository(private val database: Database) {    suspend fun findById(id: String): User? {        return database.query("SELECT * FROM users WHERE id = ?", id).singleOrNull { row ->            User(row.string("id"), row.boolean("is_premium"))        }    }}

使用 Testcontainers 的集成测试:

import io.kotest.core.spec.style.StringSpecimport io.kotest.matchers.shouldBeimport org.testcontainers.containers.PostgreSQLContainerimport org.testcontainers.junit.jupiter.Containerimport org.testcontainers.junit.jupiter.Testcontainers

@Testcontainersclass UserRepositoryIntegrationTest : StringSpec({

@Container val postgres = PostgreSQLContainer<Nothing>("postgres:15").apply { withDatabaseName("testdb") withUsername("test") withPassword("test") }

"should

博客

书籍推荐