Service层fetchGenreById方法测试失败,返回null求助排查
问题:Service层fetchGenreById方法测试返回null的排查与解决
问题背景
要测试的Service层方法:
@Override public GenreResponse fetchGenreById(Long genreId) { return convertGenreToGenreResponse(findGenreEntityByGenreId(genreId)); } private GenreResponse convertGenreToGenreResponse(Genre genre) { return modelMapper.map(genre, GenreResponse.class); } private Genre findGenreEntityByGenreId(long genreId) { return genreRepository.findByGenreId(genreId) .orElseThrow(() -> new ObjectNotFoundException("Genre with " + genreId + " id not found!")); }
编写的测试代码:
@ExtendWith(MockitoExtension.class) class GenreCrudServiceTest { @Mock private ModelMapper mockModelMapper; @Mock private GenreRepository mockGenreRepository; private GenreCrudService genreCrudService; @BeforeEach void setUp() { MockitoAnnotations.openMocks(this); genreCrudService = new GenreCrudServiceImpl(mockModelMapper, mockGenreRepository); } @Test public void GenreCrudService_FetchGenreById_ReturnsGenreResponse() { // Arrange long genreId = 1; Genre genre = Genre.builder() .genreId(genreId) .title("testTitle") .build(); Mockito.when(mockGenreRepository.findByGenreId(any(Long.class))).thenReturn(Optional.of(genre)); // Act GenreResponse genreResponse = genreCrudService.fetchGenreById(genreId); // Assert Assertions.assertThat(genreResponse).isNotNull(); }
测试报错:
Expecting actual not to be null java.lang.AssertionError: Expecting actual not to be null
原因分析
你只Mock了GenreRepository的行为,但**ModelMapper是用@Mock创建的模拟对象,Mockito对模拟对象的未指定行为默认返回null**。
在convertGenreToGenreResponse方法中调用modelMapper.map(genre, GenreResponse.class)时,因为没有给这个方法设置返回值,所以返回null,最终导致fetchGenreById返回null,断言失败。
解决方案
给mockModelMapper.map方法添加Mock行为,指定它在接收Genre对象和GenreResponse.class时返回一个非null的GenreResponse实例:
修正后的测试代码:
@ExtendWith(MockitoExtension.class) class GenreCrudServiceTest { @Mock private ModelMapper mockModelMapper; @Mock private GenreRepository mockGenreRepository; private GenreCrudService genreCrudService; @BeforeEach void setUp() { MockitoAnnotations.openMocks(this); genreCrudService = new GenreCrudServiceImpl(mockModelMapper, mockGenreRepository); } @Test public void GenreCrudService_FetchGenreById_ReturnsGenreResponse() { // Arrange long genreId = 1; Genre genre = Genre.builder() .genreId(genreId) .title("testTitle") .build(); // 准备预期返回的GenreResponse实例 GenreResponse expectedResponse = GenreResponse.builder() .genreId(genreId) .title("testTitle") .build(); // Mock Repository的查询行为 Mockito.when(mockGenreRepository.findByGenreId(any(Long.class))).thenReturn(Optional.of(genre)); // Mock ModelMapper的转换行为 Mockito.when(mockModelMapper.map(any(Genre.class), eq(GenreResponse.class))).thenReturn(expectedResponse); // Act GenreResponse genreResponse = genreCrudService.fetchGenreById(genreId); // Assert Assertions.assertThat(genreResponse).isNotNull(); // 还可以进一步断言返回的对象和预期一致 Assertions.assertThat(genreResponse.getGenreId()).isEqualTo(genreId); Assertions.assertThat(genreResponse.getTitle()).isEqualTo("testTitle"); }
补充说明
- 使用
any(Genre.class)匹配任意Genre类型的参数,eq(GenreResponse.class)精确匹配Class类型参数,确保Mock的行为准确触发。 - 如果需要验证
modelMapper.map是否被正确调用,可以在断言部分添加:Mockito.verify(mockModelMapper, times(1)).map(genre, GenreResponse.class);
内容的提问来源于stack exchange,提问作者Denis Lebenkov
相关产品推荐
相关产品推荐

