HandlerInterceptorAdapter Testing

We showed how to use HandlerInterceptorAdapter within your spring MVC application and as your mappings get more complicated you should consider writing unit tests to validate that the correct handler is being applied to URL. Spring Framework 3.2 release included first class support for testing Spring MVC applications is broken into two categories of tests; integration and mocking. The integration approach is more of full on integration test as it loads your entire configuration and the latter just mocks controllers without loading configuration. Since TestContext frameworks caches spring configuration your first test will take a hit but each one after should be fairly speedy. The example below will show how how to validate that a request contains a handler in the execution chain.

In our post on how to use spring handler interceptors post we registered NavigationHandlerInterceptor that should be executed for each request except anything that starts with /api:

@Configuration
public class ApplicationConfigurerAdapter extends WebMvcConfigurerAdapter {

    @Override
    public void addInterceptors(final InterceptorRegistry registry) {

        registry.addInterceptor(new NavigationHandlerInterceptor())
                .addPathPatterns("/**").excludePathPatterns("/api/**");
    }

}

Once spring loads context we can get a handle on the applicationContext to get RequestMappingHandlerMapping. RequestMappingHandlerMapping provides a way to get all of your @RequestMappings on @Controllers and method levels. Next we will generate a MockHttpServletRequest with a random URL and look up the handler for the given request. Since multiple handlers could be contained in the HandlerExecutionChain.getInterceptors() we want to validate that NavigationHandlerInterceptor is in the execution path so we will filter the results by class type. If you are on java 8 you could switch out the guava optional with java 8 Optional. The second test is to validate that an /api request doesn't contain the interceptor and match the pattern provided to excludePathPatterns.

@Configuration
@WebAppConfiguration
@SpringApplicationConfiguration(classes=Application.class)
@RunWith(SpringJUnit4ClassRunner.class)
public class HandlerInterceptorTest extends BaseSpringIntegration {

    @Autowired
    ApplicationContext applicationContext;

    @Test
    public void interceptor_request_all() throws Exception {

        RequestMappingHandlerMapping mapping = (RequestMappingHandlerMapping) applicationContext
                .getBean("requestMappingHandlerMapping");
        assertNotNull(mapping);

        MockHttpServletRequest request = new MockHttpServletRequest("GET",
                "/test");

        HandlerExecutionChain chain = mapping.getHandler(request);

        Optional<NavigationHandlerInterceptor> containsHandler = FluentIterable
                .from(Arrays.asList(chain.getInterceptors()))
                .filter(NavigationHandlerInterceptor.class).first();

        assertTrue(containsHandler.isPresent());
    }

    @Test
    public void interceptor_request_api() throws Exception {

        RequestMappingHandlerMapping mapping = (RequestMappingHandlerMapping) applicationContext
                .getBean("requestMappingHandlerMapping");
        assertNotNull(mapping);

        MockHttpServletRequest request = new MockHttpServletRequest("GET",
                "/api/whatever");

        HandlerExecutionChain chain = mapping.getHandler(request);

        Optional<NavigationHandlerInterceptor> containsHandler = FluentIterable
                .from(Arrays.asList(chain.getInterceptors()))
                .filter(NavigationHandlerInterceptor.class).first();

        assertFalse(containsHandler.isPresent());
    }
}