0

I learning Spring Boot web application with .jsp, and I'm struggling a lot with the testing concepts. From the SO and YT guides I implemented the Mockito thing, but honestly I do not clearly undesrtand how does it work.
I have a Registration form with 4 fields for name, lastname, email and password. This POST request is handled by the registerAction method in RegisterController. In this method I have two self-written validators for email and password. The tests should handle the cases when User data are given properly and if the errors are sent when inputs are not correct.
I tried to write tests for the controller but I'm constantly getting an exception NullPointerExpection. Looking into the debugger, the User object sent from the testing class has null attributes, which probably is the reason the exceptions.
Testing class:

@SpringBootTest
@AutoConfigureMockMvc
class RegisterControllerTest {

    @Autowired
    private WebApplicationContext wac;

    @MockBean
    private UserService userService;

    @Autowired
    private Gson gson;

    @Autowired
    private MockMvc mockMvc;


    @BeforeEach
    void setUp() {
        initMocks(this);
        this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac)
          .apply(springSecurity()).build();
    }

    @Test
    void show_register_action() throws Exception {
        User user = prepareUserEmpty();

        this.mockMvc.perform(post("/adduser")
                .contentType(MediaType.APPLICATION_JSON)
                .content(gson.toJson(user)))
                .andDo(print())
                .andExpect(status().isOk());
    }

    private User prepareUserEmpty(){
        User user = new User();
        user.setEmail("");
        user.setPassword("");
        user.setName("");
        user.setLastName("");

        return user;
    }
}

RegisterController:

@Controller public class RegisterController {

    @Autowired
    private UserService userService;

    @Autowired
    private EmailSender emailSender;

    @Autowired
    MessageSource messageSource;    // Allows to obtain messages from message.properties to Java code

    @POST
    @RequestMapping(value = "/adduser")
    public String registerAction(User user, BindingResult result, Model model, Locale locale){  // BindingResult for validation, Locale for messageSource

        String returnPage = "register";

        User userExist = userService.findUserByEmail(user.getEmail());

        new UserRegisterValidator().validate(user, result);
        new UserRegisterValidator().validateEmailExist(userExist, result);

        if (!(result.hasErrors())){
            userService.saveUser(user);
            model.addAttribute("message", messageSource.getMessage("user.register.success.email", null, locale));

            returnPage = "index";
        }

        return returnPage;
    } }

Validators:

public class UserRegisterValidator implements Validator {

    @Override
    public boolean supports(Class <?> cls){
        return User.class.equals(cls);
    }

    @Override
    public void validate(Object obj, Errors errors){
        User u = (User) obj;

        ValidationUtils.rejectIfEmpty(errors, "name", "error.userName.empty");
        ValidationUtils.rejectIfEmpty(errors, "lastName", "error.userLastName.empty");
        ValidationUtils.rejectIfEmpty(errors, "email", "error.userEmail.empty");
        ValidationUtils.rejectIfEmpty(errors, "password", "error.userPassword.empty");

        if (!u.getEmail().equals(null)){
            boolean isMatch = AppdemoUtils.checkEmailOrPassword(AppdemoConstants.EMAIL_PATTERN, u.getEmail());
            if (!isMatch)
                errors.rejectValue("email", "error.userEmailIsNotMatch");
        }

        if (!u.getPassword().equals(null)){
            boolean isMatch = AppdemoUtils.checkEmailOrPassword(AppdemoConstants.PASSWORD_PATTERN, u.getPassword());
            if (!isMatch)
                errors.rejectValue("password", "error.userPasswordIsNotMatch");
        }
    }

    public void validateEmailExist(User user, Errors errors){
        if (user != null)
            errors.rejectValue("email", "error.userEmailExist");
    }

}
  • Don't autowire `MockMvc` _and_ create your own `MockMvc` and overwrite it. Additionally, just never use `standaloneSetup`; it doesn't provide an accurate environment for testing (e.g., JSON configuration). – chrylis -cautiouslyoptimistic- Feb 08 '20 at 06:52
  • I've erased @Autowired and changed code at `void setUp()` to `this.mockMvc = MockMvcBuilders.standaloneSetup(new RegisterController()).build();`. Nothing changed, `User` with `null` values is send and exception thrown. @chrylis -on strike- – zanstaszek9 Feb 08 '20 at 13:19
  • Use _only_ autowired `MockMvc` _Never_ use `standaloneSetup`. (In this case, your problem is [exactly this one](https://stackoverflow.com/questions/19896870/why-is-my-spring-autowired-field-null) with your `new RegisterController()`.) – chrylis -cautiouslyoptimistic- Feb 08 '20 at 22:56
  • Even with erasing `setUp` function, having no `standaloneSetup` and making `MockMvc` an `@Autowired`, the test is failed in same spot - User's fields are null. @chrylis -on strike – zanstaszek9 Feb 09 '20 at 05:25
  • Convert to constructor injection on your bean (you can't use it on the test case, unfortunately, but you can on all your business objects) and see if the problem identifies itself. – chrylis -cautiouslyoptimistic- Feb 09 '20 at 07:08
  • I've added `@MockBean private RegisterController registerController;` and it started to work, the correct User object with certain parameters is passed. Although, validations methods do not return any errors (ex. for empty email field), and I've wroten a test to check if the page's title is correct, and it shows that its empty. `this.mockMvc.perform(get("/register")).andDo(print()) .andExpect(status().isOk()) .andExpect(model().attribute("title", "")) ; ` – zanstaszek9 Feb 09 '20 at 19:41

0 Answers0