使用Mockito测试Sping Boot Service时出现Wanted但未调用的错误

pepwfjgg  于 9个月前  发布在  其他
关注(0)|答案(1)|浏览(98)

我在使用Mockito为PostService类编写测试时遇到了这个Wanted but not invoked错误。错误消息表明,从发布存储库调用保存方法时发生了一些错误。下面是错误消息:

Wanted but not invoked:
postRepository.save(
    com.example.justatest.post.Post@6edaa77a
);
-> at com.example.justatest.post.PostServiceTest.shouldUpdatePost(PostServiceTest.java:139)

However, there were exactly 2 interactions with this mock:
postRepository.findById(
    c74dd65f-2438-4137-9d6d-a664a3f95621
);
-> at com.example.justatest.post.PostService.update(PostService.java:36)

postRepository.save(
    com.example.justatest.post.Post@5bfc257
);
-> at com.example.justatest.post.PostService.update(PostService.java:45)

Wanted but not invoked:
postRepository.save(
    com.example.justatest.post.Post@6edaa77a
);
-> at com.example.justatest.post.PostServiceTest.shouldUpdatePost(PostServiceTest.java:139)

However, there were exactly 2 interactions with this mock:
postRepository.findById(
    c74dd65f-2438-4137-9d6d-a664a3f95621
);
-> at com.example.justatest.post.PostService.update(PostService.java:36)

postRepository.save(
    com.example.justatest.post.Post@5bfc257
);
-> at com.example.justatest.post.PostService.update(PostService.java:45)

该错误似乎是由于modelMapper.map方法的调用与更新方法期间PostService类中的调用之间不匹配而发生的。我已经查看了错误消息,但不确定如何解决此问题。下面是相关代码:

服务等级:

@Service
@RequiredArgsConstructor
public class PostService {
    private final PostRepository postRepository;
    private final ModelMapper modelMapper;

    public Optional<PostResponseDto> update(UUID uuid, PostRequestDto postRequestDto) {
        Optional<Post> postOptional = postRepository.findById(uuid);

        if (postOptional.isEmpty()) {
            return Optional.empty();
        }

        Post post = postOptional.get();
        modelMapper.map(postRequestDto, post);

        return Optional.of(modelMapper.map(postRepository.save(post), PostResponseDto.class));
    }

    // ... (other methods)
}

测试类别:

@ExtendWith(MockitoExtension.class)
class PostServiceTest {
    @Mock
    private PostRepository postRepository;

    @Mock
    private ModelMapper modelMapper;

    @InjectMocks
    private PostService postService;
    private Post post;

    @BeforeEach
    void setUp() {
        this.post = new Post(UUID.randomUUID(), "title", "description");
    }

    @Test
    void shouldUpdatePost() {
        PostRequestDto mockPostRequestDto = new PostRequestDto("Updated Title", "Updated Description");
        Post mockUpdatedPost = new Post(post.getId(), mockPostRequestDto.getTitle(), mockPostRequestDto.getDescription());
        PostResponseDto mockPostResponseDto = new PostResponseDto(mockUpdatedPost.getId(), mockUpdatedPost.getTitle(), mockUpdatedPost.getDescription());

        doReturn(Optional.of(post)).when(postRepository).findById(post.getId());
        doNothing().when(modelMapper).map(mockPostRequestDto, post);
        doReturn(mockUpdatedPost).when(postRepository).save(post);
        doReturn(mockPostResponseDto).when(modelMapper).map(mockUpdatedPost, PostResponseDto.class);

        Optional<PostResponseDto> updatedPostOptional = postService.update(post.getId(), mockPostRequestDto);

        assertTrue(updatedPostOptional.isPresent());
        PostResponseDto updatedPost = updatedPostOptional.get();

        assertEquals(mockPostResponseDto.getId(), updatedPost.getId());
        assertEquals(mockPostResponseDto.getTitle(), updatedPost.getTitle());
        assertEquals(mockPostResponseDto.getDescription(), updatedPost.getDescription());

        verify(postRepository, times(1)).findById(post.getId());
        verify(postRepository, times(1)).save(mockUpdatedPost);
        verify(modelMapper, times(1)).map(mockPostRequestDto, post);
        verify(modelMapper, times(1)).map(mockUpdatedPost, PostResponseDto.class);
    }
}

我无法确定导致此问题的原因以及如何解决它。如能帮助理解这一问题并找到解决办法,将不胜感激。

a11xaf1n

a11xaf1n1#

您已经将存储库设置为返回post,然后由服务方法保存:

// stub:
doReturn(Optional.of(post)).when(postRepository).findById(post.getId());

// service:
Optional<Post> postOptional = postRepository.findById(uuid);
// ...
return Optional.of(modelMapper.map(
  postRepository.save(post), // <-- saved here
  PostResponseDto.class));

但是,您要验证save是否已使用mockUpdatePost调用,这是一个差异示例:

verify(postRepository, times(1)).save(mockUpdatedPost);

这也可以从错误消息中看出:

Wanted but not invoked:
postRepository.save(
    com.example.justatest.post.Post@6edaa77a // <-- instance 6edaa77a
);
-> at com.example.justatest.post.PostServiceTest.shouldUpdatePost(PostServiceTest.java:139)

However, there were exactly 2 interactions with this mock:
...

postRepository.save(
    com.example.justatest.post.Post@5bfc257 // <-- instance 5bfc257
);
-> at com.example.justatest.post.PostService.update(PostService.java:45)

修复您的verify调用以期望正确的示例:

verify(postRepository).save(post);

PS.当在mock仓库上调用时,你使用的是正确的post示例:

doReturn(mockUpdatedPost).when(postRepository).save(post);

使用Mockito的严格的调用模式(较新版本中的默认模式),如果没有调用存根方法,测试将失败,因此verify调用实际上是多余的(但您可能仍然更喜欢它来显式地澄清您的意图)。

相关问题