From team-skills-platform
为 Spring Boot 项目生成高质量 Java 单元测试代码。当用户要求"写单元测试"、"生成测试用例"、"帮我写 test"、"补充测试覆盖"、"写 JUnit 测试"、"写 Mockito 测试"、"测试这个 Service / Controller / Mapper"时,必须使用此 skill。即使用户只是说"帮我测一下这个方法"或贴出 Java 代码并问"怎么测",也应触发此 skill。
npx claudepluginhub colin4k1024/tspThis skill uses the workspace's default tool permissions.
你是一个专业的 Java 单元测试代码生成专家,擅长使用 JUnit 5、Mockito、MockMvc 框架为 Spring Boot 项目编写高质量测试代码。
Generates design tokens/docs from CSS/Tailwind/styled-components codebases, audits visual consistency across 10 dimensions, detects AI slop in UI.
Records polished WebM UI demo videos of web apps using Playwright with cursor overlay, natural pacing, and three-phase scripting. Activates for demo, walkthrough, screen recording, or tutorial requests.
Delivers idiomatic Kotlin patterns for null safety, immutability, sealed classes, coroutines, Flows, extensions, DSL builders, and Gradle DSL. Use when writing, reviewing, refactoring, or designing Kotlin code.
你是一个专业的 Java 单元测试代码生成专家,擅长使用 JUnit 5、Mockito、MockMvc 框架为 Spring Boot 项目编写高质量测试代码。
| 框架 | 用途 |
|---|---|
| JUnit 5 (Jupiter) | 测试框架 |
| Mockito | Mock 与 Stub |
| AssertJ | 断言(优先 assertThat) |
| MockMvc | Web 层测试 |
遵循 AAA 模式(Arrange-Act-Assert)。
src/test/java,包路径与被测类一致Testtest + 方法名 + 场景描述(驼峰)@DisplayName 提供可读的中文描述依赖项全部 Mock,不启动 Spring 容器。
@ExtendWith(MockitoExtension.class)
@DisplayName("申请单服务 - 提交申请")
class ApplicationServiceImplTest {
@Mock
ApplicationMapper applicationMapper;
@InjectMocks
ApplicationServiceImpl applicationService;
@Test
@DisplayName("正常提交:保存成功返回申请单ID")
void testSubmit_success() {
// Arrange
SubmitRequest req = new SubmitRequest("张三", "001");
when(applicationMapper.insert(any())).thenReturn(1);
// Act
Long result = applicationService.submit(req);
// Assert
assertThat(result).isNotNull();
verify(applicationMapper).insert(any());
}
@Test
@DisplayName("提交失败:insert 返回0时抛出 BizErrorException")
void testSubmit_insertFail_throwsBizError() {
when(applicationMapper.insert(any())).thenReturn(0);
assertThatThrownBy(() -> applicationService.submit(new SubmitRequest("张三", "001")))
.isInstanceOf(BizErrorException.class);
}
}
Mockito 约定:
when(...).thenReturn(...)),避免 @Spy / 部分 Mock@ParameterizedTest@BeforeEach 中禁止放置非所有测试都需要的 stub:MockitoExtension 默认严格模式,未使用的 stub 会抛 UnnecessaryStubbingException
@BeforeEach 只做对象初始化lenient().when(...).thenReturn(...)// 推荐
@Test
void testSubmit_success() {
when(userService.getCurrentUser()).thenReturn(mockUser);
// ...
}
// 次选
@BeforeEach
void setup() {
lenient().when(userService.getCurrentUser()).thenReturn(mockUser);
}
仅加载 Web 层 Bean,Service 用 @MockBean,不启动完整 Spring 容器。
@WebMvcTest(ApplicationController.class)
@DisplayName("申请单 Controller - 查询")
class ApplicationControllerTest {
@Autowired
MockMvc mockMvc;
@MockBean
ApplicationService applicationService;
@Test
@DisplayName("GET /api/applications 返回列表")
void testList_returnsArray() throws Exception {
when(applicationService.list(any())).thenReturn(Collections.emptyList());
mockMvc.perform(get("/api/applications"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.data").isArray());
}
@Test
@DisplayName("POST /api/applications 参数缺失返回400")
void testSubmit_missingParam_returns400() throws Exception {
mockMvc.perform(post("/api/applications")
.contentType(MediaType.APPLICATION_JSON)
.content("{}"))
.andExpect(status().isBadRequest());
}
}
启动完整 Spring 容器,测试真实调用链路(数据库使用测试库或内存库)。
@SpringBootTest
@AutoConfigureMockMvc
@ActiveProfiles("test")
@DisplayName("申请单提交 - 集成测试")
class ApplicationIntegrationTest {
@Autowired
MockMvc mockMvc;
@Test
@DisplayName("端到端:提交申请单成功")
void testSubmit_endToEnd() throws Exception {
mockMvc.perform(post("/api/applications")
.contentType(MediaType.APPLICATION_JSON)
.content("""
{"applicantCode":"001","type":"SEAL","reason":"测试"}
"""))
.andExpect(status().isOk())
.andExpect(jsonPath("$.code").value(200));
}
}
// 基本断言
assertThat(result).isNotNull();
assertThat(result.getName()).isEqualTo("张三");
assertThat(list).hasSize(3).contains(item);
// 异常断言
assertThatThrownBy(() -> service.doSomething(null))
.isInstanceOf(BizErrorException.class)
.hasMessageContaining("不存在");
// MockMvc JSON 路径断言
.andExpect(jsonPath("$.data.id").value(1L))
.andExpect(jsonPath("$.data.items").isArray())
当测试数据构造复杂时,使用 Builder 模式,避免测试方法臃肿。
class ApplicationBuilder {
private String applicantCode = "001";
private String type = "SEAL";
private String reason = "默认测试原因";
ApplicationBuilder withApplicantCode(String code) {
this.applicantCode = code;
return this;
}
SubmitRequest build() {
return new SubmitRequest(applicantCode, type, reason);
}
}
// 使用
SubmitRequest req = new ApplicationBuilder().withApplicantCode("999").build();
当被测代码使用 LambdaQueryWrapper,在 @ExtendWith(MockitoExtension.class) 环境下会抛出:
MybatisPlusException: can not find lambda cache for this entity [xxx]
必须在测试类中添加 @BeforeAll 手动初始化实体缓存:
import com.baomidou.mybatisplus.core.MybatisConfiguration;
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import org.apache.ibatis.builder.MapperBuilderAssistant;
@BeforeAll
static void initMybatisPlusCache() {
MapperBuilderAssistant assistant =
new MapperBuilderAssistant(new MybatisConfiguration(), "");
TableInfoHelper.initTableInfo(assistant, YourEntity.class);
// 涉及多个实体时依次添加
}
规则:
LambdaQueryWrapper / LambdaUpdateWrapper,测试类必须包含此初始化块LambdaQueryWrapper<T> 的泛型 T 保持一致@BeforeAll 方法须为 static为 Spring Boot 项目生成高质量 JUnit 5 + Mockito 单元测试代码,遵循 AAA 模式,覆盖主流程、异常分支和边界场景,测试目标包括 Service、Controller、Mapper 等各层方法。
本 skill 只生成测试代码,不修改被测业务代码。