使用 Kotlin 和 JUnit 测试 Java 代码 – 教程
Kotlin 与 Java 完全互操作,这意味着您可以使用 Kotlin 为 Java 代码编写测试,并与同一项目中的现有 Java 测试一起运行。
在本教程中,您将学习如何:
- 配置 Java–Kotlin 混合项目,以使用 JUnit 运行测试。
- 添加用于验证 Java 代码的 Kotlin 测试。
- 使用 Maven 或 Gradle 运行测试。
在开始之前,请确保您具备以下条件:
- 已内置 Kotlin 插件的 IntelliJ IDEA(社区版或终极版),或安装了 Kotlin 扩展程序 的 VS Code。
- Java 17 或更高版本
配置项目
在您的 IDE 中,从版本控制系统中克隆示例项目:
texthttps://github.com/kotlin-hands-on/kotlin-junit-sample.git导航至
initial模块并查看项目结构:textkotlin-junit-sample/ ├── initial/ │ ├── src/ │ │ ├── main/java/ # Java 源代码 │ │ └── test/java/ # Java 中的 JUnit 测试 │ ├── pom.xml # Maven 配置 │ └── build.gradle.kts # Gradle 配置initial模块包含一个简单的 Java 版 Todo 应用程序,并带有一个测试。在同一目录下,打开您的构建文件并更新其内容以支持 Kotlin:
xml- 在
<properties>部分,设置 Kotlin 版本。 - 在
<dependencies>部分,添加 JUnit Jupiter 依赖项以运行测试。 - 在
<build><plugins>部分,应用将<extensions>设置为true的kotlin-maven-plugin。它会自动向构建中添加相应的执行和kotlin-stdlib依赖项。 - 当使用启用了扩展的 Kotlin Maven 插件时,您不需要在
<build><pluginManagement>部分添加maven-compiler-plugin。
kotlin// build.gradle.kts group = "org.jetbrains.kotlin" version = "1.0-SNAPSHOT" description = "kotlin-junit-complete" java.sourceCompatibility = JavaVersion.VERSION_17 plugins { application kotlin("jvm") version "2.3.0" } kotlin { jvmToolchain(17) } application { mainClass.set("org.jetbrains.kotlin.junit.App") } repositories { mavenCentral() } dependencies { implementation("com.gitlab.klamonte:jexer:1.6.0") testImplementation(kotlin("test")) testImplementation(libs.org.junit.jupiter.junit.jupiter.api) testImplementation(libs.org.junit.jupiter.junit.jupiter.params) testRuntimeOnly(libs.org.junit.jupiter.junit.jupiter.engine) testRuntimeOnly(libs.org.junit.platform.junit.platform.launcher) } tasks.test { useJUnitPlatform() }- 在
plugins {}块中,添加kotlin("jvm")插件。 - 设置 JVM 工具链版本以匹配您的 Java 版本。
- 在
dependencies {}块中,添加kotlin.test库,它提供了 Kotlin 的测试实用程序并与 JUnit 集成。
Kotlin/JVM 支持最新的稳定 JUnit 版本 JUnit 6。您可以在
gradle/libs.versions.toml版本目录中找到它。如果您通常更喜欢使用版本目录,甚至可以在其中添加
kotlin("jvm")插件:toml# gradle/libs.versions.toml [versions] kotlin = "2.3.0" junit = "6.0.3" [libraries] org-junit-jupiter-junit-jupiter-api = { module = "org.junit.jupiter:junit-jupiter-api", version.ref = "junit" } org-junit-jupiter-junit-jupiter-params = { module = "org.junit.jupiter:junit-jupiter-params", version.ref = "junit" } org-junit-jupiter-junit-jupiter-engine = { module = "org.junit.jupiter:junit-jupiter-engine", version.ref = "junit" } org-junit-platform-junit-platform-launcher = { module = "org.junit.platform:junit-platform-launcher" } [plugins] kotlinJvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }- 在
在您的 IDE 中重新加载构建文件。
有关构建文件设置的更多详细说明,请参阅项目配置。
添加您的第一个 Kotlin 测试
位于 initial/src/test/java 中的 TodoItemTest.java 测试已经验证了应用的基础功能:项目创建、默认值、唯一 ID 和状态更改。
您可以通过添加验证仓库级行为的 Kotlin 测试来扩大测试覆盖范围:
导航至相同的测试源目录
initial/src/test/java。在与 Java 测试相同的包中创建一个
TodoRepositoryTest.kt文件。创建包含字段声明和设置函数的测试类:
kotlinpackage org.jetbrains.kotlin.junit import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Assertions import org.junit.jupiter.api.Test import org.junit.jupiter.api.DisplayName internal class TodoRepositoryTest { lateinit var repository: TodoRepository lateinit var testItem1: TodoItem lateinit var testItem2: TodoItem @BeforeEach fun setUp() { repository = TodoRepository() testItem1 = TodoItem("Task 1", "Description 1") testItem2 = TodoItem("Task 2", "Description 2") } }- JUnit 注解在 Kotlin 中的工作方式与在 Java 中相同。
- 在 Kotlin 中,
lateinit关键字允许声明随后初始化的非 null 属性。这有助于避免在测试中使用可空类型 (TodoRepository?)。
在
TodoRepositoryTest类中添加一个测试,以检查初始仓库状态及其大小:kotlin@Test @DisplayName("Should start with empty repository") fun shouldStartEmpty() { Assertions.assertEquals(0, repository.size()) Assertions.assertTrue(repository.all.isEmpty()) }- 与 Java 的静态导入不同,Jupiter 的
Assertions是作为一个类导入的,并用作断言函数的限定符。 - 在 Kotlin 中,您可以使用
repository.all将 Java 的 getter 方法作为属性进行访问,而不是调用.getAll()。
- 与 Java 的静态导入不同,Jupiter 的
编写另一个测试来验证所有项目的副本行为:
kotlin@Test @DisplayName("Should return defensive copy of items") fun shouldReturnDefensiveCopy() { repository.add(testItem1) val items1 = repository.all val items2 = repository.all Assertions.assertNotSame(items1, items2) Assertions.assertThrows( UnsupportedOperationException::class.java ) { items1.clear() } Assertions.assertEquals(1, repository.size()) }- 要从 Kotlin 类获取 Java 类对象,请使用
::class.java。 - 您可以将复杂的断言拆分为多行,而无需使用任何特殊的延续字符。
- 要从 Kotlin 类获取 Java 类对象,请使用
添加一个测试来验证通过 ID 查找项目:
kotlin@Test @DisplayName("Should find item by ID") fun shouldFindItemById() { repository.add(testItem1) repository.add(testItem2) val found = repository.getById(testItem1.id()) Assertions.assertTrue(found.isPresent) Assertions.assertEquals(testItem1, found.get()) }Kotlin 可以顺利地与 Java
OptionalAPI 配合使用。它会自动将 getter 方法转换为属性,这就是为什么这里将isPresent()方法作为属性访问的原因。编写一个测试来验证项目移除机制:
kotlin@Test @DisplayName("Should remove item by ID") fun shouldRemoveItemById() { repository.add(testItem1) repository.add(testItem2) val removed = repository.remove(testItem1.id()) Assertions.assertTrue(removed) Assertions.assertEquals(1, repository.size()) Assertions.assertTrue(repository.getById(testItem1.id()).isEmpty) Assertions.assertTrue(repository.getById(testItem2.id()).isPresent) } @Test @DisplayName("Should return false when removing non-existent item") fun shouldReturnFalseForNonExistentRemoval() { repository.add(testItem1) val removed = repository.remove("non-existent-id") Assertions.assertFalse(removed) Assertions.assertEquals(1, repository.size()) }在 Kotlin 中,您可以链式调用方法和属性访问,例如
repository.getById(id).isEmpty。
您可以向
TodoRepositoryTest测试类中添加更多测试以覆盖更多功能。请参阅示例项目中complete模块的完整源代码。
运行测试
运行 Java 和 Kotlin 测试以验证您的项目是否按预期工作:
使用装订区域图标运行测试:

您还可以使用命令行从
initial目录运行所有项目测试:bashmvn testbash./gradlew test通过更改其中一个变量值来检查测试是否正常工作。例如,修改
shouldAddItem测试以使其期望一个错误的仓库大小:kotlin@Test @DisplayName("Should add item to repository") fun shouldAddItem() { repository.add(testItem1) Assertions.assertEquals(2, repository.size()) // 从 1 更改为 2 Assertions.assertTrue(repository.all.contains(testItem1)) }再次运行测试并验证其是否失败:

您可以在示例项目的
complete模块中找到带有测试的完整配置项目。
