我正在尝试编写测试以确保我的登录控制器具有某些模型属性并运行某些服务方法。
当我为这个控制器运行测试时,我只得到一个错误,分别是loginForm和registerForm测试
javax.servlet.ServletException: Circular view path [login]: would dispatch back to the current handler URL [/login] again. Check your ViewResolver setup! (Hint: This may be the result of an unspecified view, due to default view name generation.)
和
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.)
但是当我运行其他控制器(主控制器)时,我没有收到这些错误!
TemplateConfig.java
@Configuration
public class TemplateConfig {
@Bean
public SpringResourceTemplateResolver templateResolver() {
final SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver();
templateResolver.setCacheable(false);
templateResolver.setPrefix("classpath:/templates/");
templateResolver.setSuffix(".html");
return templateResolver;
}
@Bean
public SpringTemplateEngine templateEngine() {
final SpringTemplateEngine springTemplateEngine = new SpringTemplateEngine();
springTemplateEngine.addTemplateResolver(templateResolver());
springTemplateEngine.addDialect(new SpringSecurityDialect());
return springTemplateEngine;
}
@Bean
public ThymeleafViewResolver viewResolver() {
final ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
viewResolver.setTemplateEngine(templateEngine());
viewResolver.setOrder(1);
return viewResolver;
}
}
LoginController.java
@Controller
public class LoginController {
//todo: create test
@Autowired
private UserService userService;
@RequestMapping(path = "/login", method = RequestMethod.GET)
public String loginForm(Model model, HttpServletRequest request) {
model.addAttribute("user", new User());
try {
Object flash = request.getSession().getAttribute("flash");
model.addAttribute("flash", flash);
request.getSession().removeAttribute("flash");
} catch (Exception ex) {}
return "login";
}
@RequestMapping(path = "/register", method = RequestMethod.GET)
public String registerForm(Model model){
UserDto user = new UserDto();
model.addAttribute("user", user);
return "register";
}
//todo: add test
@RequestMapping(path = "/register", method = RequestMethod.POST)
public String createUser(@ModelAttribute("user") @Valid UserDto userDto, BindingResult bindingResult, RedirectAttributes redirectAttributes){
//todo: add autologin
if(bindingResult.hasErrors()){
redirectAttributes.addFlashAttribute("user", new UserDto());
redirectAttributes.addFlashAttribute("org.springframework.validation.BindingResult.user", bindingResult);
return "redirect:/register";
}
//todo: add tests for exceptions
try {
userService.registerNewUserAccount(userDto);
} catch (UsernameAlreadyExistsException ex) {
redirectAttributes.addFlashAttribute("user", new UserDto());
redirectAttributes.addFlashAttribute("flash", new FlashMessage(ex.getMessage(), FlashMessage.Status.FAILURE));
return "redirect:/register";
} catch (EmailAlreadyExistsException ex) {
redirectAttributes.addFlashAttribute("user", new UserDto());
redirectAttributes.addFlashAttribute("flash", new FlashMessage(ex.getMessage(), FlashMessage.Status.FAILURE));
return "redirect:/register";
}
return "redirect:/login";
}
@ExceptionHandler(RoleNotFoundException.class)
public String roleNotFound(Model model, Exception ex){
model.addAttribute("ex", ex);
return "error";
}
}
LoginControllerTest.java
@RunWith(MockitoJUnitRunner.class)
public class LoginControllerTest {
private MockMvc mockMvc;
@InjectMocks
private LoginController controller;
@Mock
private UserService service;
@Before
public void setUp() throws Exception {
mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
}
@Test
public void loginForm_ShouldIncludeNewUserInModel() throws Exception {
mockMvc.perform(get("/login"))
.andExpect(status().isOk())
.andExpect(view().name("login"))
.andExpect(model().attribute("user", instanceOf(User.class)));
}
@Test
public void registerForm_ShouldIncludeNewUserDtoInModel() throws Exception {
mockMvc.perform(get("/register"))
.andExpect(status().isOk())
.andExpect(view().name("register"))
.andExpect(model().attribute("user", instanceOf(UserDto.class)));
}
@Test
public void createUser_ShouldCreateUserWithValidCredentials() throws Exception {
UserDto userDto = new UserDto.UserDtoBuilder()
.withEmail("example@gmail.com")
.withUsername("username12")
.withPassword("password12")
.build();
mockMvc.perform(
post("/register")
.requestAttr("user", userDto)
).andExpect(redirectedUrl("/login"));
verify(service).registerNewUserAccount(any(UserDto.class));
}
@Test
public void createUser_ShouldRedirectToRegisterWhenUsernameAlreadyExistsExceptionIsThrown() throws Exception {
UserDto userDto = new UserDto.UserDtoBuilder()
.withEmail("example@gmail.com")
.withUsername("username12")
.withPassword("password12")
.build();
//Can't use when method since service.registerNewUserAccount return type is void
doThrow(new UsernameAlreadyExistsException()).when(service).registerNewUserAccount(any(UserDto.class));
mockMvc.perform(
post("/register")
.requestAttr("user", userDto)
).andExpect(redirectedUrl("/register"));
verify(service).registerNewUserAccount(any(UserDto.class));
}
@Test
public void createUser_ShouldRedirectToRegisterWhenEmailAlreadyExistsExceptionIsThrown() throws Exception {
UserDto userDto = new UserDto.UserDtoBuilder()
.withEmail("example@gmail.com")
.withUsername("username12")
.withPassword("password12")
.build();
//Can't use when method since service.registerNewUserAccount return type is void
doThrow(new EmailAlreadyExistsException()).when(service).registerNewUserAccount(any(UserDto.class));
mockMvc.perform(
post("/register")
.requestAttr("user", userDto)
).andExpect(redirectedUrl("/register"));
verify(service).registerNewUserAccount(any(UserDto.class));
}
@Test
public void createUser_ShouldIncludeNewUserDtoAndBindingResultInModelWhenValidationErrors() throws Exception {
UserDto userDto = new UserDto.UserDtoBuilder()
.withEmail("dsa")
.withUsername("d")
.withPassword(" ")
.build();
mockMvc.perform(post("/register").requestAttr("user", userDto))
.andExpect(view().name("register"))
.andExpect(status().isOk())
.andExpect(model().attribute("user", new UserDto()))
.andExpect(model().attribute("org.springframework.validation.BindingResult.user", instanceOf(BindingResult.class)));
}
}
异常
14:44:31.138 [main] DEBUG org.springframework.web.servlet.view.InternalResourceView - Added model object 'user' of type [com.smarttodo.model.User] to request in view with name 'null'
14:44:31.138 [main] DEBUG org.springframework.web.servlet.view.InternalResourceView - Removed model object 'flash' from request in view with name 'null'
14:44:31.138 [main] DEBUG org.springframework.web.servlet.view.InternalResourceView - Added model object 'org.springframework.validation.BindingResult.user' of type [org.springframework.validation.BeanPropertyBindingResult] to request in view with name 'null'
14:44:31.140 [main] DEBUG org.springframework.test.web.servlet.TestDispatcherServlet - Error rendering view [org.springframework.web.servlet.view.InternalResourceView: unnamed; URL [login]] in DispatcherServlet with name ''
javax.servlet.ServletException: Circular view path [login]: would dispatch back to the current handler URL [/login] again. Check your ViewResolver setup! (Hint: This may be the result of an unspecified view, due to default view name generation.)
at org.springframework.web.servlet.view.InternalResourceView.prepareForRendering(InternalResourceView.java:205)
at org.springframework.web.servlet.view.InternalResourceView.renderMergedOutputModel(InternalResourceView.java:145)
at org.springframework.web.servlet.view.AbstractView.render(AbstractView.java:303)
at org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1282)
at org.springframework.test.web.servlet.TestDispatcherServlet.render(TestDispatcherServlet.java:105)
at org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1037)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:980)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:897)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:861)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:622)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
at org.springframework.test.web.servlet.TestDispatcherServlet.service(TestDispatcherServlet.java:65)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
at org.springframework.mock.web.MockFilterChain$ServletFilterProxy.doFilter(MockFilterChain.java:167)
at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:134)
at org.springframework.test.web.servlet.MockMvc.perform(MockMvc.java:155)
at com.smarttodo.web.controller.LoginControllerTest.loginForm_ShouldIncludeNewUserInModel(LoginControllerTest.java:57)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
答案 0 :(得分:1)
您的ViewResolver
未用于测试。您必须使用当前的ApplicationContext
或在测试中指定ViewResolver
。
使用ApplicationContext
,您可以将以下内容添加到LoginControllerTest.java中,注意我将其更改为与SpringJUnit4ClassRunner
一起运行以使其正常工作。
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes={TemplateConfig.class})
@WebAppConfiguration
@Autowired
WebApplicationContext wac;
@Before
public void setUp() throws Exception {
mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
}
或者使用ViewResolver
您只需要更改setUp()
方法。
@Before
public void setUp() throws Exception {
mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setPrefix("/WEB-INF/jsp/view/");
viewResolver.setSuffix(".jsp");
mockMvc = MockMvcBuilders.standaloneSetup(new LoginController())
.setViewResolvers(viewResolver)
.build();
}