Sunday, January 18, 2009

Spring Integration Testing for Web

I am building OSGi web based (partially) application. As usual when you touch new area of technology (especially new technology) it tends to be problematic.

Today problem I have faced three weeks ago. How to test web controller.
Maybe its not a problem at all (you can configure everything manually), but I really wanted to use spring support for testing.

If you're preparing a test for IoC managed components you can use this fact (if you need more information refere to spring documentation).

To build your context you can use Spring TestFramework annotations.

package com.example;

@RunWith(SpringJUnit4ClassRunner.class)
// ApplicationContext will be loaded from "classpath:/com/example/MyTest-context.xml"
@ContextConfiguration
public class MyTest {
// class body...
}

You can also specify where to look for context(s) definition(s). And at the moment you're redy to use @Autowired annotation

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"/META-INF/spring/module-context.xml", "/test-context.xml"})
public class ControllerTest {
@Autowired
private Controller controller;
}

As you can see I'am using application context and test context (which is used for components normally reached via OSGi). But if we leave it this way It won't work.
The reason is that Controller needs web context and Spring test mechanism provides normal one. But there is a solution. We can provide our context loader which is able to provide required context.
@ContextConfiguration(locations = {"/META-INF/spring/module-context.xml", "/test-context.xml"}, loader = XmlWebApplicationContextLoader.class)

And here is XmlWebApplicationContextLoader:

public class XmlWebApplicationContextLoader extends
AbstractContextLoader {
...
public final ConfigurableApplicationContext loadContext(String... locations)
throws Exception {
if (logger.isDebugEnabled()) {
logger
.debug("Loading ApplicationContext for locations ["
+ StringUtils .arrayToCommaDelimitedString(locations)
+ "].");
}
GenericApplicationContext context = new GenericWebApplicationContext();
prepareContext(context);
customizeBeanFactory(context.getDefaultListableBeanFactory());
createBeanDefinitionReader(context).loadBeanDefinitions(locations);
AnnotationConfigUtils.registerAnnotationConfigProcessors(context);
customizeContext(context);
context.refresh();
context.registerShutdownHook();
return context;
}

Now you are ready to test web controller classes. In spring framewor Http request and response mock are off the shelf.

No comments: