You need to enable JavaScript to run this app. 如何为Spring Boot的/getSUID/{pid}接口编写JUnit与Mockito测试用例
优惠活动
大模型
产品
解决方案
定价
更多

如何为Spring Boot的/getSUID/{pid}接口编写JUnit与Mockito测试用例

针对该接口的JUnit + MockMvc测试实现方案

核心思路是完全不启动真实Spring容器、不连接真实数据库,通过Mockito隔离所有外部依赖,避开之前全量容器加载带来的各类报错。

测试整体依赖梳理

这个接口运行时的外部依赖共有3类,测试时需要全部替换为Mock对象,不能执行真实逻辑:

  • JdbcTemplate:数据库查询组件,真实调用会连数据库引发超时、连接失败错误
  • QueriesUtil:SQL加载工具类,是静态方法调用,真实执行会加载本地SQL配置文件,容易报文件找不到、空指针错误
  • 数据库返回结果的RowMapper映射逻辑

测试类基础配置

采用Mockito的纯单元测试模式,搭配standalone模式的MockMvc,相比启动全量SpringBootTest的方式,启动速度快、报错点少:

@ExtendWith(MockitoExtension.class)
class StudyControllerTest {
    // 注入待测试的Controller实例,自动注入同类型的Mock依赖
    @InjectMocks
    private StudyController studyController;

    // 声明需要Mock的数据库组件
    @Mock
    private JdbcTemplate jdbcTemplate;

    private MockMvc mockMvc;

    // 每个测试方法执行前初始化MockMvc
    @BeforeEach
    void setUp() {
        // 仅注册当前测试的Controller,不加载其他Spring容器组件
        mockMvc = MockMvcBuilders.standaloneSetup(studyController).build();
    }
}

注意:很多测试报错来自使用@AutoConfigureMockMvc搭配全量@SpringBootTest启动,加载了不需要的数据库、配置类Bean导致上下文启动失败。用standaloneSetup初始化的MockMvc完全不依赖容器,稳定性更高。

核心测试方法编写(重点解决静态方法Mock问题)

针对QueriesUtil.getQuery()这类静态方法,必须用Mockito的静态Mock能力做隔离,否则测试时会执行真实的SQL加载逻辑,这也是很多人编写测试时频繁报错的核心原因:

@Test
void testGetSUID_NormalRequest() throws Exception {
    // 用try-with-resources隔离静态Mock的作用域,避免Mock值残留影响其他测试用例
    try (MockedStatic<QueriesUtil> queriesUtilMock = Mockito.mockStatic(QueriesUtil.class)) {
        // 1. Mock SQL加载逻辑的返回值
        String mockBaseSql = "SELECT PERSON_ID, MODALITY, STUDY_UID FROM STUDY WHERE PID = <:PID>";
        queriesUtilMock.when(() -> QueriesUtil.getQuery("STUDY_UID_TEST", true))
                .thenReturn(mockBaseSql);

        // 2. 构造测试入参
        String testPid = "P00123";
        // 构造模拟的数据库返回对象
        StudyUID mockStudyResult = new StudyUID(
                1001,
                "MR",
                "1.2.156.10019.2.123456"
        );
        // 3. Mock JdbcTemplate的查询返回值,不执行真实数据库查询
        when(jdbcTemplate.query(anyString(), any(RowMapper.class)))
                .thenReturn(List.of(mockStudyResult));

        // 4. 发起MockMvc请求
        mockMvc.perform(get("/getSUID/{pid}", testPid)
                        .accept(MediaType.APPLICATION_JSON))
                .andExpect(status().isOk())
                // 校验接口返回的JSON结构和值是否符合预期
                .andExpect(jsonPath("$[0].personId").value(1001))
                .andExpect(jsonPath("$[0].modality").value("MR"))
                .andExpect(jsonPath("$[0].studyUid").value("1.2.156.10019.2.123456"));

        // 5. 校验业务逻辑的交互正确性
        // 确认SQL加载时用了正确的配置key
        queriesUtilMock.verify(() -> QueriesUtil.getQuery("STUDY_UID_TEST", true), times(1));
        // 确认SQL占位符替换逻辑生效:传入的pid正确替换了SQL里的<:PID>占位符
        String expectedReplacedSql = "SELECT PERSON_ID, MODALITY, STUDY_UID FROM STUDY WHERE PID = P00123";
        verify(jdbcTemplate, times(1)).query(eq(expectedReplacedSql), any(RowMapper.class));
    }
}

常见报错排查点

  • 静态Mock没有用try-with-resources做作用域隔离,导致静态Mock值残留到其他测试用例,引发逻辑异常
  • 匹配JdbcTemplate的RowMapper参数时用了固定值匹配,因为接口里的RowMapper是lambda匿名实现,固定值匹配会识别失败,导致Mock不生效、返回null
  • 请求路径的占位符传递错误,要么路径写死和接口映射不匹配,要么动态参数没有传递给get()方法,导致404错误
  • 静态Mock的依赖版本不兼容:需要引入mockito-inline组件才能支持静态方法Mock,普通版本的Mockito默认不支持该能力

内容的提问来源于stack exchange,提问作者Neha Pal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.11.07 04:24:04