Возвращая ноль в прерываниях контроллера MockMvc

Я использую MockMvc с Mockito, опираясь в основном на весенний образец теплицы. У меня есть простой контроллер, который возвращает String viewname или null, если есть какая-то ошибка. Это хорошо работает в среде сервлетов, однако, когда я пытаюсь выполнить модульное тестирование контроллера с помощью MockMvc standaloneSetup, я получаю

javax.servlet.ServletException: Circular view path [register]: would dispatch back to the current handler URL [/register] again. Check your ViewResolver setup! (Hint: This may be the result of an unspecified view, due to default view name generation.)

Это мой контроллер

@Controller
public class SignupController {

@RequestMapping(value="/register", method=RequestMethod.GET)
public RegistrationForm createNewRegForm(){
    return new RegistrationForm();
}

/**
 * Process a signup form submission.
 * Delegate to a {@link SignupServiceImpl} to actually complete the signin transaction.
 * Redirects the new member to the application home page on successful sign-in.
 */
@RequestMapping(value="/register", method=RequestMethod.POST)
public String signup(@Validated(Registration.class) RegistrationForm form, BindingResult formBinding) {
    if(formBinding.hasErrors())
        return null;
    boolean success = signupHelper.signup(form.getUser(), formBinding);
    return (!formBinding.hasErrors() && success) ? "redirect:/" : null;
}

}

и проваленный тест:

public void signup_duplicateEmail() throws Exception {
    AccountManager accountRepository = mock(AccountManager.class);
    AccountAuthUtils authorization = mock(AccountAuthUtils.class);
    when(accountRepository.createAccount(any(User.class))).thenThrow(new EmailAlreadyOnFileException("roy@clarkson.com"));
    SignupServiceImpl gateway = new SignupServiceImpl(accountRepository, authorization);        
    SignupController signupController = new SignupController(gateway);

    MockMvc mockMvc = standaloneSetup(signupController).build();
    mockMvc.perform(post("/register").contentType(APPLICATION_FORM_URLENCODED)
                .param("user.username","habuma")
                .param("user.email","roy%40clarkson.com")
                .param("user.password", "letmein1")
                .param("confirmPassword", "letmein1"))
            .andExpect(MockMvcResultMatchers.status().isOk())
            .andExpect(MockMvcResultMatchers.forwardedUrl("/register.do"))
            .andExpect(MockMvcResultMatchers.model().hasErrors())
            .andExpect(MockMvcResultMatchers.model().attributeHasFieldErrors("registrationForm", "user.email"));
}

Простой обход кода возвращает "/register.do" вместо null для сбоев в контроллере, но я бы предпочел не менять свой код, чтобы тесты работали.

2 ответа

Решение

Я предполагаю, что причина этого различия заключается в том, что в производственном процессе вы настроили свой ViewResolver для использования "/WEB-INF/" и, возможно, суффикса. В вашей автономной тестовой настройке вы не добавляете ViewResolver, поэтому по умолчанию просто берет имя представления и превращает его в путь, после чего он понимает, что он совпадает с путем запроса.

Что касается документации по.do, у вас есть точка зрения, и мы скоро что-нибудь добавим, следите здесь.

Хорошо, после нескольких часов, когда я сломал голову, я понял.

В основном, это даст эту проблему, пока начальный URL совпадает с конечным URL. Однако вы можете обмануть его, попросив опубликовать ("register.do") (что и делает сервлет) и проверить, что он возвращает "register". Таким образом, мое решение было:

mockMvc.perform(post("/register.do").contentType(APPLICATION_FORM_URLENCODED)
            .param("user.username","habuma")
            .param("user.email","roy%40clarkson.com")
            .param("user.password", "letmein1")
            .param("confirmPassword", "letmein1"))
        .andExpect(MockMvcResultMatchers.status().isOk())
        .andExpect(MockMvcResultMatchers.forwardedUrl("register"))

И теперь он работает как в тестовой, так и в серверной среде.

PS Хотелось бы, чтобы была вся документация для всего этого.do. Я никогда по-настоящему не понимал этого после многих лет работы с ним.

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