Интеграционный тест с Mockito не покрывается, даже когда он входит в оператор else

Я пытаюсь выполнить некоторые интеграционные тесты для Rest API с Mockito в Spring Boot. Несмотря на то, что мой код в операторе else проверяется, он все равно не дает мне покрытия. Я добавил немного System.out.println(), чтобы убедиться, что код выполняется в статусе else. Когда я заглянул в консоль отладки, System.out.println() выводит в консоль, статус else выполняется, но код все еще не обнаруживается покрытием. Только оператор if обнаруживается. Я удалил оператор if-else, чтобы перейти непосредственно к коду, который был в операторе else, но по-прежнему не обнаруживается. Я предполагаю, что это может быть связано с тем, что я использую forEach или Set<>.

Класс модульного теста:


@WebMvcTest(AuthController.class)
public class AuthControllerTests {

    @Autowired
    private MockMvc mockMvc;
    @Autowired
    private ObjectMapper objectMapper;
    @MockBean
    private UserRepository userRepository;
    @MockBean
    private RoleRepository roleRepository;
    @MockBean
    private UserDetailsServiceImpl userDetailsService;
    @MockBean
    private JwtUtils jwtUtils;
    @MockBean
    PasswordEncoder encoder;
    @MockBean
    AuthenticationManager authenticationManager;

    @Test
    public void testRegisterUser() throws Exception{
        List <Role> listRoles = new ArrayList<>();
        listRoles.add(new Role(ERole.ROLE_USER));
        listRoles.add(new Role(ERole.ROLE_MODERATOR));
        listRoles.add(new Role(ERole.ROLE_ADMIN));
        Mockito.when(roleRepository.findByName(ERole.ROLE_USER)).thenReturn(java.util.Optional.ofNullable(listRoles.get(0)));
        Mockito.when(roleRepository.findByName(ERole.ROLE_MODERATOR)).thenReturn(java.util.Optional.ofNullable(listRoles.get(1)));
        Mockito.when(roleRepository.findByName(ERole.ROLE_ADMIN)).thenReturn(java.util.Optional.ofNullable(listRoles.get(2)));
        Set<String> currentRoles = new HashSet<>();
        currentRoles.add("admin");
        currentRoles.add("mod");
        currentRoles.add("user");

        SignupRequest signupRequest = new SignupRequest();
        signupRequest.setUsername("test");
        signupRequest.setEmail("test");
        signupRequest.setPassword("12341234");
        signupRequest.setRole(currentRoles);

        User user = new User(signupRequest.getUsername(),
                signupRequest.getEmail(),
                encoder.encode(signupRequest.getPassword()));

        Set<String> strRoles = signupRequest.getRole();
        System.out.println(strRoles);
        Set<Role> roles = new HashSet<>();

        if (strRoles == null) {
            Role userRole = roleRepository.findByName(ERole.ROLE_USER)
                    .orElseThrow(() -> new RuntimeException("Error: Role is not found."));
            roles.add(userRole);
            System.out.println("enters if");
        }
        else {
            strRoles.forEach(role -> {
                switch (role) {
                    case "admin":
                        Role adminRole = roleRepository.findByName(ERole.ROLE_ADMIN)
                                .orElseThrow(() -> new RuntimeException("Error: Role is not found."));
                        roles.add(adminRole);
                        System.out.println("enters case admin");
                        break;
                    case "mod":
                        Role modRole = roleRepository.findByName(ERole.ROLE_MODERATOR)
                                .orElseThrow(() -> new RuntimeException("Error: Role is not found."));
                        roles.add(modRole);
                        System.out.println("enters case mod");
                        break;
                    default:
                        Role userRole = roleRepository.findByName(ERole.ROLE_USER)
                                .orElseThrow(() -> new RuntimeException("Error: Role is not found."));
                        roles.add(userRole);
                        System.out.println("enters case user");
                }
            });
        }

        user.setRoles(roles);
        String url = "/auth/signup";

        MvcResult mvcResult = mockMvc.perform(post(url).contentType("application/json")
                .content(objectMapper.writeValueAsString(user))).andExpect(status().isOk()).andReturn();
        int status = mvcResult.getResponse().getStatus();
        System.out.println(status);
    }


}

Класс AuthController:

@PostMapping("/signup")
    public ResponseEntity<?> registerUser(@Valid @RequestBody SignupRequest signUpRequest) {
        AlreadyExistsError AlreadyExistsError = new AlreadyExistsError();

        if (userRepository.existsByUsername(signUpRequest.getUsername())) {
            AlreadyExistsError.setUserAlreadyExists(true);
        }
        if (userRepository.existsByEmail(signUpRequest.getEmail())) {
            AlreadyExistsError.setEmailAlreadyExists(true);
        }

        if (AlreadyExistsError.hasAnyErrors()){
            return ResponseEntity
                    .badRequest()
                    .body(AlreadyExistsError);
        }

        // Create new user's account
        User user = new User(signUpRequest.getUsername(), 
                             signUpRequest.getEmail(),
                             encoder.encode(signUpRequest.getPassword()));

        Set<String> strRoles = signUpRequest.getRole();
        Set<Role> roles = new HashSet<>();

        if (strRoles == null) {
            Role userRole = roleRepository.findByName(ERole.ROLE_USER)
                    .orElseThrow(() -> new RuntimeException("Error: Role is not found."));
            roles.add(userRole);
        }
        else {
            strRoles.forEach(role -> {
                switch (role) {
                case "admin":
                    Role adminRole = roleRepository.findByName(ERole.ROLE_ADMIN)
                            .orElseThrow(() -> new RuntimeException("Error: Role is not found."));
                    roles.add(adminRole);

                    break;
                case "mod":
                    Role modRole = roleRepository.findByName(ERole.ROLE_MODERATOR)
                            .orElseThrow(() -> new RuntimeException("Error: Role is not found."));
                    roles.add(modRole);

                    break;
                default:
                    Role userRole = roleRepository.findByName(ERole.ROLE_USER)
                            .orElseThrow(() -> new RuntimeException("Error: Role is not found."));
                    roles.add(userRole);
                }
            });
        }

        user.setRoles(roles);
        userRepository.save(user);

        return ResponseEntity.ok(new MessageResponse("User registered successfully!"));
    }

    @CrossOrigin
    @GetMapping("/users")
    @ResponseBody
    public List<User> searchUser(@RequestParam String username){
        return  userRepository.findByUsernameContaining(username);
    }

Как выглядит мое покрытие:

То, что вы скопировали (довольно) большой кусок вашего тестируемого кода в тестовый метод, должно быть для вас предупреждающим сигналом. Метод тестирования должен проверять только одно условие, вот и все. Таким образом, вы должны написать один выделенный тестовый метод для каждой роли, один для случаев, когда роль не задана, и один, когда задано несколько ролей.

Tom 12.12.2020 19:12

Я сделал отдельные модульные тесты для каждого условия для strRoles==null, для администратора, для мода и для пользователя, но я все еще не покрываю последние 3.

joro27 13.12.2020 10:08

Затем вы либо допустили ошибку в каждом тесте, либо не запустили тест, чтобы получить их отчет о покрытии (и вы просматриваете только отчет о покрытии теста, который не входит в ветвь «else»). Пробовали ли вы отлаживать свой контроллер во время запуска одного из новых методов тестирования?

Tom 13.12.2020 18:15
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
3
789
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ваши вызовы println говорят только о том, что вы выполняете три случая переключения в блоке else в своем тесте, но не в реальном контроллере.

Абсолютно не имеет смысла иметь большую часть кода контроллера в тесте. Кажется, это ничего не дает. Покрытие говорит вам, что то, как вы вызываете контроллер в конце вашего теста, только запускает случай, когда strRoles является null.

Ответ принят как подходящий

Моя ошибка заключалась в том, что я пропускал .content(objectMapper.writeValueAsString(user))) вместо .content(objectMapper.writeValueAsString(signuprequest))), потому что @RequestBody — это SignupRequest, а не User.

Другие вопросы по теме