You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot服务层作者数据更新单元测试返回Null问题排查

Spring Boot服务层作者更新功能单元测试Null响应问题排查

问题描述

为Spring Boot服务层的作者数据更新功能编写单元测试时,执行发现response对象返回Null,导致测试失败。已mockauthorRepository的findById方法,但问题仍存在。

测试代码

@Test
@DisplayName("Test 3: Author record Update successfully")
@Order(3)
void testUpdateAuthor_Success() {
    AuthorDTO authorDTO = new AuthorDTO();
    authorDTO.setName("Updated Author Name");

    Author existingAuthor = new Author();
    existingAuthor.setId(1L);
    existingAuthor.setName("Original Author Name");

    // Arrange
    Long authorId = 1L;
    lenient().when(authorRepository.findById(authorId)).thenReturn(Optional.of(existingAuthor));

    // Act
    ResponseEntity<ApiResponse<String>> response = authorService.updateAuthor(existingAuthor.getId(), authorDTO);

    // Assert
    // verify(authorRepository).save(existingAuthor);
    assertEquals(HttpStatus.OK, response.getStatusCode());
    assertEquals("Author record updated successfully.", Objects.requireNonNull(response.getBody()).getMessage());
    assertEquals("Updated Author Name", existingAuthor.getName());
}

服务层代码

public ResponseEntity<ApiResponse<String>> updateAuthor(Long id, @Valid AuthorDTO authorDTO) {
    logger.info("Update a author ID : {} Author Dto : {}", id, authorDTO);
    try {
        logger.info("Check existingAuthor for ID :{}", id);
        Author existingAuthor = authorRepository.findById(id).orElse(null);
        if (existingAuthor != null) {
            logger.info("Updating author ID: {} author : {}", id, authorDTO);
            existingAuthor.setName(authorDTO.getName());
            authorRepository.save(existingAuthor);
            logger.info("Updated author ID: {} author : {}", id, authorDTO);
            return ResponseUtil.buildResponse(null, "Author record updated successfully.", HttpStatus.OK);
        } else {
            logger.info("Author data not found or empty");
            return ResponseUtil.buildResponse(null, "Author data not found.", HttpStatus.NOT_FOUND);
        }
    } catch (OptimisticLockingFailureException e) {
        return ResponseUtil.buildResponse(null, "Conflict: Author record was modified or deleted by another process: Author Id :" + id + "=>" + e, HttpStatus.CONFLICT);

    } catch (Exception e) {
        logger.error("Error occurred while updating author ID: {}", id, e);
        return ResponseUtil.buildResponse(null, "Error occurred while updating author with id: '" + id, HttpStatus.INTERNAL_SERVER_ERROR);
    }
}

排查思路

  • 检查Mock注入正确性:确认测试类中authorRepository是通过@MockBean或@Mock+@InjectMocks正确注入到authorService中的,避免服务层使用真实Repository实例而非Mock对象。
  • 验证Mock参数匹配:将Mock语句改为when(authorRepository.findById(eq(authorId))).thenReturn(Optional.of(existingAuthor))(需导入org.mockito.ArgumentMatchers.eq),明确参数匹配规则,避免因参数类型或值的隐性不匹配导致Mock失效。
  • 排查ResponseUtil工具类:临时替换服务层中ResponseUtil.buildResponse的调用,直接返回new ResponseEntity<>(new ApiResponse<>(null, "Author record updated successfully."), HttpStatus.OK),若此时response不再为Null,说明工具类内部存在返回Null的逻辑问题。
  • 检查异常分支执行情况:查看测试时的日志输出,确认是否进入了某个异常分支但返回的ResponseEntity为Null;或在服务层各return语句处添加断点,跟踪实际返回的对象是否正常。
  • 移除lenient()测试:去掉lenient(),使用普通的Mock语句,lenient()会放宽Mock的校验规则,可能掩盖参数匹配失败的问题。
  • 确认参数传递正确性:在服务层updateAuthor方法开头添加日志打印logger.info("Received update request for id: {}", id),确认接收到的id与Mock的id一致,避免参数传递过程中出现意外修改。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 18:23:18