简体   繁体   中英

Struggling with unit testing and mocking

I am trying to mock the following method:

public void add(Question question) {
        String username = authenticationManager.getUsername();
        Candidate candidate = userService.getByUsername(username);

        if (!authenticationManager.hasPermission("ROLE_ADMIN")) {
            question.setStatus(QuestionStatus.WAITING);
        }

        question.setCandidate(candidate);
        questionRepository.add(question);
    }

This is my attempt:

@Test
public void add_savesQuestionWithStatusWaiting_whenSubmittedAsUser() {
    Candidate candidate = new Candidate();
    Question question = mock(Question.class);

    when(authenticationManager.getUsername()).thenReturn("andreas");
    when(userService.getByUsername("andreas")).thenReturn(candidate);
    when(authenticationManager.hasPermission("ROLE_ADMIN")).thenReturn(true);

    questionService.add(question);
    verify(question, times(0)).setStatus(any(QuestionStatus.class));
}

What I am trying to do is to test application logic. When the user does not have ROLE_ADMIN the question status will be set to waiting. Am I doing the mocking right?

In unit testing you mock every dependency that is not the part of the tested unit. In your case your unit is questionRepository and you are trying to test whether all expected interaction on the objects occur but not on the real objects but on their mocked versions. That is perfectly fine and natural approach.

So in terms of how you use mockito you are doing pretty good. What is not ok is that questionService.add is doing a way too much. 'add' suggests that it will put some object in a container and nothing else. Instead it is also doing a complex question object setup. In other words it has side effects. The result is that the number of different boundary conditions you have to test is big. That will make your tests hard to maintain in future. Look how many mocks you had to create.

If you come back to your test after some time and you will try to figure out what is it doing will this be simple ? I also think that the test name is not reflecting what is actually tested. For me 'add_savesQuestionWithStatusWaiting_whenSubmittedAsUser' implies that I should expect that at the end question should be saved with status set to 'waiting' instead you use verify to check if there was no call to setStatus().

I would try to refactor the add method code so all it does is element insertion into queryService. Then I would test different boundary conditions for questionService ( for example how it will behave when null will be provided ). I would also move setup of question to a different layer of your application and have that tested in a different unit.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM