JUnit 5 常见语法及使用场景

16 阅读3分钟

1. JUnit 5 介绍

JUnit 5 由 JUnit Platform、JUnit Jupiter、JUnit Vintage 组成:

  • JUnit Platform:运行测试的底层平台
  • JUnit Jupiter:JUnit 5 的新 API
  • JUnit Vintage:兼容 JUnit 4/3 测试

JUnit 5 vs. JUnit 4

  • JUnit 5 更灵活,支持 Lambda、动态测试、扩展 API
  • JUnit 4 结构简单,但不如 JUnit 5 强大

2. 依赖配置

Gradle 中引入 JUnit 5:

dependencies {
    testImplementation("org.junit.jupiter:junit-jupiter:5.9.3")
}

3. JUnit 5 主要注解

注解作用
@Test标记一个测试方法
@BeforeEach每个测试方法执行前运行
@AfterEach每个测试方法执行后运行
@BeforeAll在所有测试前执行(静态方法)
@AfterAll在所有测试后执行(静态方法)
@DisplayName自定义测试名称
@Disabled禁用测试
@ParameterizedTest参数化测试
@ExtendWith扩展 JUnit 功能
@Nested组织嵌套测试类
@Tag给测试分组
@TestInstance变更测试实例生命周期

4. 基础用法

(1)基本测试

import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Test

class ExampleTest {

    @Test
    fun `addition should be correct`() {
        val result = 3 + 5
        assertEquals(8, result)
    }
}

JUnit 5 使用 assertEquals 断言,更简洁
支持 Kotlin 反引号方法名,更直观


(2)测试生命周期

import org.junit.jupiter.api.*

@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class LifecycleTest {

    @BeforeAll
    fun setupAll() {
        println("在所有测试前执行")
    }

    @BeforeEach
    fun setupEach() {
        println("在每个测试前执行")
    }

    @Test
    fun test1() {
        println("执行 test1")
    }

    @Test
    fun test2() {
        println("执行 test2")
    }

    @AfterEach
    fun tearDownEach() {
        println("在每个测试后执行")
    }

    @AfterAll
    fun tearDownAll() {
        println("在所有测试后执行")
    }
}

@BeforeAll / @AfterAll 适用于 初始化资源(如数据库连接)
@BeforeEach / @AfterEach 适用于 每个测试前后的清理


(3)跳过测试

@Test
@Disabled("暂时禁用")
fun ignoredTest() {
    println("不会执行")
}

@Disabled 可以 临时跳过 失败的测试


5. 断言(Assertions)

JUnit 5 提供了 Assertions 类:

import org.junit.jupiter.api.Assertions.*

@Test
fun `test assertions`() {
    assertEquals(10, 5 + 5, "计算结果错误")
    assertTrue(5 > 2, "条件应为真")
    assertFalse(5 < 2, "条件应为假")
    assertNotNull("Hello", "对象不应为空")
}

支持多个断言,提供错误提示信息


(1)组合断言(assertAll

@Test
fun `test multiple assertions`() {
    assertAll(
        { assertEquals(2, 1 + 1) },
        { assertTrue("hello".startsWith("h")) },
        { assertFalse("hello".endsWith("z")) }
    )
}

多个断言同时执行,避免一个失败后跳过其他检查


(2)异常断言

@Test
fun `test exception`() {
    val exception = assertThrows<IllegalArgumentException> {
        throw IllegalArgumentException("Invalid input")
    }
    assertEquals("Invalid input", exception.message)
}

检测方法是否抛出指定异常


6. 参数化测试

(1)单个参数

import org.junit.jupiter.params.ParameterizedTest
import org.junit.jupiter.params.provider.ValueSource

class ParameterizedExampleTest {

    @ParameterizedTest
    @ValueSource(strings = ["hello", "world"])
    fun `test with multiple values`(input: String) {
        assertTrue(input.length > 3)
    }
}

一次性测试多个输入值,避免重复代码


(2)多个参数

import org.junit.jupiter.params.provider.CsvSource

@ParameterizedTest
@CsvSource("2,3,5", "3,5,8", "6,7,13")
fun `test addition`(a: Int, b: Int, expected: Int) {
    assertEquals(expected, a + b)
}

CsvSource 允许多个参数传递


7. 嵌套测试

JUnit 5 支持嵌套测试:

import org.junit.jupiter.api.Nested

class OuterTest {

    @Test
    fun `outer test`() {
        println("外部测试")
    }

    @Nested
    inner class InnerTest {
        @Test
        fun `inner test`() {
            println("内部测试")
        }
    }
}

组织复杂测试,清晰分层


8. 测试超时

import org.junit.jupiter.api.Timeout
import java.util.concurrent.TimeUnit

@Test
@Timeout(value = 2, unit = TimeUnit.SECONDS)
fun `test should finish within 2 seconds`() {
    Thread.sleep(1000) // 1 秒,未超时
}

超时限制防止测试卡死


9. 扩展 JUnit

(1)自定义扩展

import org.junit.jupiter.api.extension.*

class MyExtension : BeforeTestExecutionCallback {
    override fun beforeTestExecution(context: ExtensionContext?) {
        println("测试开始前执行")
    }
}

@ExtendWith(MyExtension::class)
class ExtensionTest {
    @Test
    fun `test with custom extension`() {
        println("测试运行中")
    }
}

扩展 JUnit,添加自定义行为


10. 运行测试

# 运行所有测试
./gradlew test

# 运行指定测试
./gradlew test --tests "com.example.MyTest"

# 生成测试报告
./gradlew jacocoTestReport

总结

功能JUnit 5 方式
基本测试@Test
生命周期管理@BeforeEach@AfterEach
跳过测试@Disabled
断言assertEqualsassertAll
参数化测试@ParameterizedTest
嵌套测试@Nested
超时@Timeout
自定义扩展@ExtendWith

使用 JUnit 5,可以写出 更高效、可读性更强的测试 🚀