Я пытаюсь выполнить некоторые интеграционные тесты для 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);
}
Как выглядит мое покрытие:
Я сделал отдельные модульные тесты для каждого условия для strRoles==null, для администратора, для мода и для пользователя, но я все еще не покрываю последние 3.
Затем вы либо допустили ошибку в каждом тесте, либо не запустили тест, чтобы получить их отчет о покрытии (и вы просматриваете только отчет о покрытии теста, который не входит в ветвь «else»). Пробовали ли вы отлаживать свой контроллер во время запуска одного из новых методов тестирования?
Ваши вызовы println говорят только о том, что вы выполняете три случая переключения в блоке else в своем тесте, но не в реальном контроллере.
Абсолютно не имеет смысла иметь большую часть кода контроллера в тесте. Кажется, это ничего не дает. Покрытие говорит вам, что то, как вы вызываете контроллер в конце вашего теста, только запускает случай, когда strRoles
является null
.
Моя ошибка заключалась в том, что я пропускал .content(objectMapper.writeValueAsString(user)))
вместо .content(objectMapper.writeValueAsString(signuprequest)))
, потому что @RequestBody
— это SignupRequest
, а не User
.
То, что вы скопировали (довольно) большой кусок вашего тестируемого кода в тестовый метод, должно быть для вас предупреждающим сигналом. Метод тестирования должен проверять только одно условие, вот и все. Таким образом, вы должны написать один выделенный тестовый метод для каждой роли, один для случаев, когда роль не задана, и один, когда задано несколько ролей.