关于 java-junit
面向 Java 开发的测试指导技能,涵盖 JUnit 5/6、AssertJ 和 Mockito。它强调遵循项目现有约定、编写确定性测试,并安全处理测试失败。
主要功能
- 01识别现有构建与测试约定
- 02JUnit 5 和 6 指导
- 03断言与 Mockito 实践
- 04确定性测试方法
- 05单元与集成测试配置
- 06测试安全与验证规则
适用场景
- 01为现有 Java 项目添加测试
- 02消除不稳定测试中的时间或随机性
- 03拆分单元与集成测试运行
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ github/ awesome-copilot --skill java-junit安装后在 Claude Code 中输入/java-junit确认已加载。
附带文件references/assertj-and-mockito.mdreferences/build-setup.md
详细介绍
使用 JUnit 5/6、AssertJ 和 Mockito 进行 Java 测试
不依赖特定框架的指南,助你编写快速、确定性的单元测试。使用 Spring 切片测试时,请用 spring-boot-testing(如果已安装);需要在 Docker 中使用真实数据库或消息代理时,请用 java-testcontainers;遇到无法解释的故障时,请用 java-debugging。
首先:检测现状,不要强加选择
- 阅读
pom.xml/build.gradle*:JUnit 版本(junit-jupiter、junit-bom,或从 Spring Boot BOM 继承)、断言库、Mockito、Surefire/Failsafe 版本以及 Java 发布版本。 - 沿用
src/test/java中已有的约定(命名、断言库、静态导入、模拟风格)。如果项目尚未使用 AssertJ、Mockito 或 JaCoCo,未经询问不要引入。 - 切勿隐式升级 JUnit 主版本;升级应作为单独任务处理(如果已安装,请参阅
java-upgrade)。
JUnit 5 与 JUnit 6
| JUnit 5(最新版本为 5.14.x) | JUnit 6(已发布 6.0;当前版本为 6.1.x) | |
|---|---|---|
| Java 基线版本 | 8 | 17(已在发布的 Gradle 模块元数据中核实) |
| 版本编号 | Platform 为 1.x,Jupiter 为 5.x,Vintage 为 5.x | Platform、Jupiter 和 Vintage 共用一个版本号 |
| API | org.junit.jupiter.api.* | 包名相同;本技能中的 Jupiter 测试在 5.14.4 和 6.0.3 上均可直接编译并通过 |
| 6.0 中移除的内容 | MethodOrderer.Alphanumeric、已弃用的双参数 InvocationInterceptor.interceptDynamicTest(Invocation, ExtensionContext) 重载(三参数版本仍保留)、junit.jupiter.tempdir.scope、@CsvFileSource(lineSeparator) | |
| CSV | univocity-parsers | FastCSV:解析更严格(结束引号后不能有其他字符);表头字段选项现在也适用于表头 |
| 其他 | junit-jupiter-migrationsupport 已弃用;无效的枚举式配置值现在会导致发现失败;@Nested 类的顺序确定但不直观 |
来源:JUnit 6.0.0 发布说明(https://docs.junit.org/6.0.0/release-notes.html)。请阅读目标版本的说明(https://docs.junit.org/current/release-notes/),并优先以其为准。JUnit 4 测试需要 Vintage 引擎;不要在同一个类中混用 org.junit.Test 和 org.junit.jupiter.api.Test。
依赖(JUnit 5 和 6 相同;已使用 Maven 和 Gradle 验证):导入 org.junit:junit-bom,然后声明 org.junit.jupiter:junit-jupiter(聚合了 api、params、engine),并将作用域设为 test。Gradle 9 还要求添加 testRuntimeOnly("org.junit.platform:junit-platform-launcher")(已验证:若缺少此项,测试执行器会因 "Failed to load JUnit Platform" 而失败),并设置 tasks.test { useJUnitPlatform() }。Maven 需要 Surefire 3.x(已使用 3.6.0 验证)。
断言
遵循项目使用的库。使用纯 Jupiter 时,规则如下:期望值放在第一个参数;消息使用延迟计算的 Supplier;使用 assertAll、assertThrowsExactly 和超时断言。(独立的 instructions/java-junit5-assertions.instructions.md 资源中有更完整的说明,但本技能不会安装该资源。)如果项目使用 AssertJ,集合、字符串和异常优先使用它;相关模式(软断言、assertThatThrownBy、extracting、containsExactly、usingRecursiveComparison)见 references/assertj-and-mockito.md。
- 断言结果和状态,而不是内部方法被调用的次数。
- 比较值;避免单独使用
assertNotNull。 - 切勿捕获
AssertionError/Exception来让测试通过。
Mock(Mockito)
- Mock 跨边界的协作者(仓储、HTTP 客户端、时钟、消息发送器)。不要 mock 值对象、记录类、集合、
String或被测类;应使用真实实例或简单的伪对象。 - 如果交互具有状态,优先使用手写伪对象,而不是 mock。
- 使用
@ExtendWith(MockitoExtension.class),并搭配@Mock/@InjectMocks/@Captor。此处默认启用严格存根,因此未使用的存根会导致测试失败(UnnecessaryStubbingException)。请修正测试;只有在共享设置确有理由时,才使用@MockitoSettings(strictness = Strictness.LENIENT)放宽限制。 - Mockito 5 默认使用内联 mock maker。在 JDK 21+ 上,它可能会自行附加并打印动态 Agent 警告。对于 Mockito 5.14.0+,应改为将
mockito-core注册为-javaagent(Maven 和 Gradle 的配置见references/assertj-and-mockito.md,已在 JDK 21 和 25 上验证)。请先检查实际解析的版本:较早的 5.x JAR 缺少Premain-Class,不能用作 Agent。升级前请先征求同意;否则请使用已安装版本对应的文档中所述的插桩配置。 - Mockito 5 要求 Java 11+。其默认内联 mock maker 不适用于 GraalVM 原生镜像,此时应使用子类 mock maker(Mockito 5.0.0 发行说明:https://github.com/mockito/mockito/releases/tag/v5.0.0)。
- 避免使用
mockStatic/mockConstruction;应在静态调用外封装一个接口。
确定性
- 时间:注入
java.time.Clock(Clock.fixed(...)),并调用Instant.now(clock);避免在被测代码中使用Instant.now()/LocalDate.now()。 - 随机性:注入使用固定种子的
Random/RandomGenerator;如果生成了种子,请记录该种子。 - 不要依赖默认区域设置、时区、文件编码、网络或墙上时钟休眠。请显式设置它们(较新的 6.x 版本增加了内置的区域设置/时区/系统属性扩展;请检查对应版本的发行说明,否则使用 try/finally)。
单元测试与集成测试
单元测试(*Test) | 集成测试(*IT) | |
|---|---|---|
| Maven | Surefire,mvn test | Failsafe,mvn verify |
| Gradle | test 任务 | 单独的 integrationTest 任务(JVM Test Suite),并接入 check |
| 速度 | 毫秒级,无 I/O | 可能使用 Docker/DB |
Surefire 默认匹配 *Test、Test*、*Tests、*TestCase;Failsafe 匹配 *IT、IT*、*ITCase。Failsafe 需要绑定 integration-test 和 verify 目标,并通过 mvn verify 运行,而不是 mvn test。也可以通过 @Tag 拆分。数据库和消息代理请参阅 java-testcontainers;Spring 切片请参阅 spring-boot-testing。完整构建代码片段见 references/build-setup.md。
覆盖率与变异测试(可选)
- JaCoCo:仅在项目已使用或用户提出要求时添加。与 Surefire/Failsafe 搭配使用时,应使用
<argLine>@{argLine} ...</argLine>,以免覆盖 JaCoCo Agent。 - 覆盖率是用于发现异味的指标,而非目标;绝不要为了提高数值而添加没有断言的测试,也不要添加项目尚未采用的覆盖率门槛。
- PIT(变异测试)速度较慢;仅在项目已使用或用户提出要求时,针对变更的类运行(参见
references/build-setup.md,其中记录了已验证的 pitest-maven + JUnit 5 插件运行情况)。
Agent 护栏
- 绝不为了让测试通过而删除、注释掉、添加
@Disabled、削弱(放宽断言、扩大容差、吞掉异常)或跳过失败的测试。查明原因。 - 判断是测试还是生产代码有误。如果修复会改变生产行为,请先停下并询问用户;如果测试表达的预期显然已过时,请说明这一点并提出修改建议。
- 不要添加
-DskipTests、-Dmaven.test.skip、-x test或failIfNoTests=false来让构建通过。 - 不要模拟被测类,也不要断言模拟对象的内部状态来“证明”正确性。
- 先运行范围最小的测试,再运行完整构建:
- Maven:
mvn -q -Dtest=OrdersTest test(单个方法:-Dtest='OrdersTest#place_should_saveAndNotify_when_itemValid'),然后运行mvn verify。 - Gradle:
./gradlew test --tests 'demo.OrdersTest',然后运行./gradlew check。 如果存在项目包装器,请优先使用(./mvnw、./gradlew)。
- Maven:
- 对于不稳定的测试:通过重复运行来复现,然后消除非确定性因素(时间、顺序、共享状态、异步等待);不要添加重试。
- 新代码应在现有测试旁边添加新测试,并保持相同风格:正常路径、边界情况、错误情况。
参考资料
references/assertj-and-mockito.md:AssertJ 模式、Mockito 严格性/参数捕获器/Agent 设置,以及何时不应使用模拟。references/build-setup.md:JUnit 5/6、Failsafe 拆分、JaCoCo、PIT 的 Maven 和 Gradle(Kotlin DSL)设置。