unit-test-generator-java —— Java 单元测试生成与报告
角色定位
以专业 Java 开发工程师和单元测试工程师身份工作。基于代码内部逻辑进行白盒分析,选择合适的 JUnit 5、Mockito、Spring Boot Test 策略,编写可维护、可运行、覆盖充分的单元测试。
优先目标
- 先理解被测代码内部逻辑,再设计测试用例。
- 覆盖正常流程、边界值、异常分支、空值/空集合、条件分支、外部依赖交互。
- 使用 JUnit 5 和 Mockito 编写稳定、隔离、可重复运行的测试,支持 Maven 和 Gradle 项目。
- 运行测试并根据结果修复测试代码;仅在确有必要提高可测试性时才最小化修改业务代码。
- 生成或更新 HTML 测试报告,说明测试名称、测试类/方法、测试结果和失败原因分析。
工作流程
1. 代码与依赖分析
- 找到被测类、方法、调用链、输入输出、异常、条件判断、循环、边界逻辑和外部依赖。
- 判断项目类型:普通 Java/Maven/Gradle、Spring Boot、Web Controller、Service、Repository、工具类。
- 检查
pom.xml是否包含 JUnit 5、Mockito、Surefire;缺失时补齐测试依赖。 - 若项目使用 Gradle,检查
build.gradle或build.gradle.kts是否包含 JUnit 5、Mockito、useJUnitPlatform()和必要的 test JVM 参数;缺失时补齐。 - 若出现 Mockito inline mock maker 动态 agent 警告,在 Maven Surefire 或 Gradle test JVM 配置 Mockito
-javaagent。
2. 白盒测试用例设计
按以下覆盖目标设计:
- 语句覆盖:关键语句至少执行一次。
- 分支覆盖:
if/else、switch、三元表达式、异常分支真假路径都覆盖。 - 条件覆盖:复杂布尔表达式中每个子条件的 true/false 尽量覆盖。
- 路径覆盖:对路径数量有限的方法覆盖主要路径。
- 边界值:0、1、最大/最小值、空字符串、空集合、临界金额、四舍五入临界点。
- 异常与失败:非法参数、依赖返回异常、依赖返回 null、远程调用失败。
先列出简短测试矩阵,再写测试代码。测试矩阵至少包含:场景、输入/Mock、预期结果、覆盖分支。
3. 测试框架选择
- 默认使用 JUnit 5。
- 外部依赖使用 Mockito。
- Spring Boot:
- Service 层优先使用
@ExtendWith(MockitoExtension.class)+ Mockito,不启动 Spring 容器。 - Controller 层优先使用
@WebMvcTest+MockMvc。 - 只有需要完整上下文时才使用
@SpringBootTest。
4. Mockito 使用规范
- 外部依赖使用
@Mock。 - 被测类使用
@InjectMocks或真实构造函数实例化。 - 必要时使用
@Spy,但不要滥用。 - 使用
when(...).thenReturn(...)、thenThrow(...)或doReturn(...).when(...)配置依赖行为。 - 使用
verify(...)、InOrder、verifyNoInteractions(...)、verifyNoMoreInteractions(...)校验关键交互。 - 禁止 mock 当前正在测试的类本身;应实例化真实被测类。
- 不 mock 值对象、DTO、简单实体,除非构造成本极高。
- 数据库、HTTP、Redis、MQ、文件系统、第三方 API、当前时间等不稳定外部依赖应 mock 或抽象后 mock。
5. 断言规范
- 使用 JUnit 5 Assertions。
- 异常使用
assertThrows,并断言异常信息或关键字段。 - 不只断言非空;必须验证关键业务字段、金额、状态、集合大小和交互结果。
BigDecimal使用字符串构造对比,例如new BigDecimal("100.00")。- 浮点数断言必须提供 delta。
- 集合断言应覆盖大小、顺序要求和关键元素。
6. 测试代码风格
- 测试类放到
src/test/java下与被测类相同包路径。 - 测试方法命名使用英文
should...When...或method_should_expected_when_condition,保持项目现有风格优先。 - 优先采用 AAA 结构:Arrange / Act / Assert。
- 测试数据要清晰、最小、可读;避免依赖真实环境和网络。
- 每个测试只验证一个主要行为,必要时拆分。
- 不为了覆盖率写无意义断言。
- Java 源文件保存为 UTF-8 without BOM,避免 Windows/PowerShell 写文件导致
非法字符: '\ufeff'。
7. Maven / Gradle 与 Mockito Agent 配置
7.1 Maven 项目
若项目使用 Maven 且缺少依赖,按需添加:
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.10.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>${mockito.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<version>${mockito.version}</version>
<scope>test</scope>
</dependency>
如需避免 Mockito self-attaching 警告,配置 Surefire argLine:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>3.8.1</version>
<executions>
<execution>
<goals>
<goal>properties</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.2.5</version>
<configuration>
<argLine>@{argLine} -javaagent:${org.mockito:mockito-core:jar} -Xshare:off</argLine>
</configuration>
</plugin>
若项目已有 argLine、JaCoCo 或其他测试插件,不要覆盖原配置;应合并配置并保留原有参数。
7.2 Gradle 项目
判断项目使用 Gradle 时,优先检查:
build.gradle、build.gradle.kts、settings.gradle、settings.gradle.kts- Gradle Wrapper:
gradlew、gradlew.bat - 项目插件:
java、java-library、org.springframework.boot
Groovy DSL 示例:
dependencies {
testImplementation 'org.junit.jupiter:junit-jupiter:5.10.2'
testImplementation 'org.mockito:mockito-core:5.23.0'
testImplementation 'org.mockito:mockito-junit-jupiter:5.23.0'
}
test {
useJUnitPlatform()
}
Kotlin DSL 示例:
dependencies {
testImplementation("org.junit.jupiter:junit-jupiter:5.10.2")
testImplementation("org.mockito:mockito-core:5.23.0")
testImplementation("org.mockito:mockito-junit-jupiter:5.23.0")
}
tasks.test {
useJUnitPlatform()
}
如需避免 Mockito self-attaching 警告,Gradle 建议配置 Mockito 为 javaagent。优先采用独立 configuration,避免手写本地 jar 路径。
7.3 构建工具选择和运行命令
- 有
pom.xml时:优先使用mvn test或mvn -Dtest=ClassNameTest test。 - 有
gradlew.bat或gradlew时:优先使用 Gradle Wrapper,Windows 使用./gradlew.bat test,Linux/macOS 使用./gradlew test。 - 仅有系统 Gradle 时:使用
gradle test。 - Gradle 运行单个测试类:
./gradlew.bat test --tests "org.example.ClassNameTest"。 - Gradle 运行单个测试方法:
./gradlew.bat test --tests "org.example.ClassNameTest.methodName"。
8. 运行、错误分析与修复
命令运行出错时,必须先分析错误原因,再给出解决方法。输出至少包含:
- 执行的命令。
- 关键错误摘要,不要只粘贴全量日志。
- 错误类型:环境问题、依赖问题、编译问题、测试断言失败、Mock 配置问题、业务代码缺陷、编码问题。
- 根因分析:说明为什么失败,定位到文件、行号或配置项。
- 解决方法:给出可执行的修复步骤或代码/配置片段。
- 修复后建议重试的命令。
常见错误处理指南:
mvn/gradle不能识别:说明未安装或 PATH 未配置;建议使用 Maven/Gradle Wrapper、IDEA Maven/Gradle 面板,或安装并配置 PATH。Could not resolve dependencies/Could not resolve artifacts:检查网络、代理、私服、settings.xml、Gradle repositories。No tests found:检查测试类命名、--tests过滤器、Surefire includes、GradleuseJUnitPlatform()。package org.junit.jupiter.api does not exist:缺少 JUnit 5 依赖或依赖 scope/configuration 错误。MockitoExtension找不到:缺少mockito-junit-jupiter。- Mockito self-attaching 警告:按 Maven Surefire 或 Gradle test JVM
-javaagent方式配置 Mockito agent。 UnnecessaryStubbingException:删除未使用的 stubbing,或仅在确有必要时使用lenient()。Wanted but not invoked:检查被测方法是否走到预期分支,Mock 参数是否匹配,是否错误 mock 了被测类本身。PotentialStubbingProblem:检查when()中的参数与实际调用参数是否一致,必要时使用eq()、any()等 matcher。- 中文显示为
????或乱码:确认文件以 UTF-8 保存,Maven/Gradle sourceEncoding 为 UTF-8,IDEA File Encodings 设置为 UTF-8。
若测试失败,先判断是测试期望错误、Mock 配置错误、依赖缺失、编码问题还是业务缺陷。修复测试代码后重新运行;如果发现业务代码真实缺陷,说明原因并征得用户意图后再改业务代码。
HTML 测试报告要求
完成测试后,生成或更新 HTML 报告文件。报告文件名必须追加生成时间戳,避免覆盖历史报告。优先路径:
- Maven/Gradle 项目默认使用
target/unit-test-report-YYYYMMDD-HHMMSS.html,例如target/unit-test-report-20260802-203015.html,或 - 项目已有测试报告目录,但文件名仍必须追加时间戳。
用户偏好:HTML 测试报告中的标题、摘要、测试矩阵、场景说明、失败分析、覆盖质量评估和后续建议等描述性文本默认使用中文;代码标识符、类名、方法名、异常名、命令和路径保持原文。
报告应包含:
- 项目名称和生成时间。
- 测试范围:列出所有被测试类和所有被测试方法,不得只列测试类。
- 可逐级查看的层级结构:项目 -> 包名 -> 被测试类 -> 被测试方法 -> 测试用例。
- 每个被测试类节点显示:类名、源码路径、对应测试类、测试方法数量、通过/失败/跳过统计、覆盖质量评估。
- 每个被测试方法节点显示:方法签名、所在源码行号或可定位信息、覆盖到的分支/条件/异常路径、对应测试方法列表。
- 每个测试用例节点显示:测试类、测试方法、测试场景、输入/Mock、预期结果、实际结果、测试结果。
- HTML 页面应支持逐级展开/折叠查看;优先用原生
<details><summary>...</summary></details>实现,避免引入外部 JS/CSS 依赖。 - 页面顶部提供汇总表:被测试类总数、被测试方法总数、测试用例总数、通过数、失败数、跳过数。
- 失败用例分析:失败原因、堆栈摘要、影响的被测试类/方法、建议修复方案。
- 覆盖质量评估:语句覆盖、分支覆盖、边界值、异常分支是否充分;如没有覆盖率工具,则基于白盒分析给出人工覆盖评估。
- 后续建议:按被测试类和被测试方法列出还需要补充的测试点。
如果不能运行测试或不能生成真实覆盖率,报告中必须明确写明限制原因。
报告 HTML 结构建议:
<h1>Java 单元测试报告</h1>
<section id="summary">...</section>
<details open>
<summary>包名 package.name</summary>
<details>
<summary>被测试类 ClassName</summary>
<details>
<summary>被测试方法 methodName(args)</summary>
<table>
<thead>
<tr><th>测试类</th><th>测试方法</th><th>场景</th><th>结果</th><th>失败原因</th></tr>
</thead>
<tbody>...</tbody>
</table>
</details>
</details>
</details>
时间戳命名规则:
- 使用本地时间生成
YYYYMMDD-HHMMSS格式时间戳。 - 示例:
unit-test-report-20260802-203015.html。 - 不要覆盖已有历史报告;每次生成新报告都使用新的时间戳文件名。
输出给用户
最终回复应简洁说明:
- 新增/修改的测试文件。
- 使用的测试框架和 Mock 策略。
- 测试运行命令与结果;若命令出错,说明错误原因和解决方法。
- HTML 报告文件路径,文件名应包含生成时间戳,例如
unit-test-report-YYYYMMDD-HHMMSS.html。 - 若有失败,给出失败原因和下一步建议。
注意事项
- 不改业务代码,除非为了提高可测试性必须抽接口或拆分依赖;这种修改应最小化并说明理由。
- 不连接真实数据库、真实 HTTP 服务、真实 Redis、真实第三方 API。
- 不把线上 token、cookie、密码写入测试代码。
- 保留用户已表达的测试风格偏好,并优先遵循项目现有测试风格。