1

I'm using Spring 3.1.1.RELEASE and JUnit 4.11. I setup my JUnit tests like so

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({ "classpath:test-context.xml" })
public class MySpringTest 
{
    protected MockHttpServletRequest request;
    protected MockHttpServletResponse response;
    protected MockHttpSession session;

    @Autowired
    protected RequestMappingHandlerAdapter handlerAdapter;

    @Autowired
    protected RequestMappingHandlerMapping handlerMapping;

When testing controllers, I have this line to verify that the view the controller's method is returning is the right view …

import static org.springframework.test.web.ModelAndViewAssert.assertViewName;
...
final ModelAndView mav = submitMyForm(…);
    assertViewName(mav, "folder/myView");
    ...

protected ModelAndView submitMyForm(… params ...) throws Exception {
    request = new MockHttpServletRequest();
    response = new MockHttpServletResponse();
    request.setRequestURI("/myurl");
    request.setMethod("POST");
    request.addParameter("param1", param1);
    ...

    final Object handler = handlerMapping.getHandler(request).getHandler();
    return handlerAdapter.handle(request, response, handler);
} 

My question is, once I verify the view returned my the controller is the expected view, how do I verify it won't result in a 404? The main problem I'm gaving now is testing whether or not the view actually maps to an underlying page in my WAR file.

Dave
  • 15,639
  • 133
  • 442
  • 830
  • 3
    I think in the context of a "unit" test, what you're testing should end after you get the expected view back from the controller - which is what you have. To test request from the controller action invocation to the resulting view/contents itself is more of an integration test - where you only care about the params you give the resulting view (and not necessarily what happens in the controller action). – ikumen Aug 20 '13 at 16:59
  • Ok, so if I had used the words "integration test" instead of "unit test", what's the answer? – Dave Aug 22 '13 at 16:31
  • I think you can't test it without starting an application server if you want to verify it won't return a 404. And this has nothing to do with unit testing. You should maybe consider having functional or integration tests using for instance Selenium. – LaurentG Aug 23 '13 at 06:15
  • Can you upgrade Spring to 3.2.x? If so, you should be able to use the added support described here: http://static.springsource.org/spring/docs/3.2.x/spring-framework-reference/html/testing.html#spring-mvc-test-framework – JoeG Aug 23 '13 at 16:48
  • This library: https://github.com/SpringSource/spring-test-mvc is now integrated inside spring 3.2, the library itself could be used with Dave's spring version – Emanuele Ivaldi Aug 23 '13 at 20:02

2 Answers2

1

why don't use spring-mvc-test and do something like this ?

@Autowired
private ViewResolver viewResolver;

// code

View view = viewResolver.resolveViewName(viewName, locale);

//assert view not null

or something like this, in wich you can check both if the view is ok and the returned status (is status 200/404?) (more code here: http://goo.gl/fMqBsl)

@Test
public void indexTest() throws Exception {

    mockMvc.perform(get("/")).andDo(print())
        .andExpect(handler().handlerType(MainController.class))
        .andExpect(handler().methodName("index"))
        .andExpect(view().name("index"))
        .andExpect(forwardedUrl("/WEB-INF/tiles/template.jsp"))
        .andExpect(status().isOk());
}
Emanuele Ivaldi
  • 1,332
  • 10
  • 15
  • Hey, regarding the line, "if(view != null){//view exists}", the view is not-null even if the underlying page isn't there (i.e. can't test for a potential 404 with that). – Dave Aug 23 '13 at 14:30
  • **Returns: the View object, or null if not found (optional, to allow for ViewResolver chaining)** <- This is from the comment of the interface, damned optional, I remembered wrong :/ – Emanuele Ivaldi Aug 23 '13 at 15:58
  • and what about using spring-test-mvc for your spring version? https://github.com/SpringSource/spring-test-mvc – Emanuele Ivaldi Aug 23 '13 at 19:18
  • How would I use spring-test-mvc to do what I want? – Dave Aug 23 '13 at 20:16
  • _'once I verify the view returned my the controller is the expected view, how do I verify it won't result in a 404?'_ you can check the expected status (like in the code I posted), it isn't what you are looking for? – Emanuele Ivaldi Aug 23 '13 at 20:25
  • Hmmm, I guess I'll have to read up more on what it does. My tests right now function as more integration tests than unit tests in as far as I don't mock the controller's response, I'm actually executing the controller's code. My first impression about what you posted in the "mockMVC" call was that it was only mocking the controller but I could be wrong about that. – Dave Aug 23 '13 at 20:49
  • The controller is not being mocked this way but you are executing its logic, if you are not using jsps you can also test the generated html – Emanuele Ivaldi Aug 23 '13 at 23:18
0

i am using standard jsp view

basically, you need to know the view resolver(s). can a specific view be resolved? that means, if you DON'T have a file called abc.xml, it might still be a valid view.

for simplicity sake, lets assume that we have only one view resolver, and, its

"org.springframework.web.servlet.view.UrlBasedViewResolver"

and here is the bean definition spring 3.2.4 documentation pdf, page 477

<bean id="viewResolver"
class="org.springframework.web.servlet.view.UrlBasedViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>

eg: the view name "page1" => /WEB-INF/jsp/page1.jsp and "admin/page2" => /WEB-INF/jsp/admin/page2.jsp

using this, you can Inject the view resolved to your junit test using @Autowired and/or @Qualifier then read the "prefix" and suffix value and find the full path like "src/main/webapp/" + prefix + viewname + suffix

and check if the file exists.

you may have multiple view resolvers, so you may want to inject the context and handle the view => filename resolution using a strategy pattern.

something like

foreach resolver
{
if i can resolve the view to a file (resolver type, viewname)
return the physical filename
else
try next resolver
}
  • We are using Spring 3.1.1.RELEASE (it's not an option to upgrade at this time) and the view resolver, "org.springframework.web.servlet.view.InternalResourceViewResolver", althouhg I'm open to using another ViewResolver supported by the 3.1.1.RELEASE version. Given this, how can I do what you suggest? – Dave Aug 23 '13 at 15:15