In order to promote a test-driven approach for development and to make testing of services implemented with the CAE application framework easier, CoreMedia ships an ease to use test add-on to be used in your tests based on Spring Testing.
Differing from the unit testing approach, it doesn't focus on testing single classes only but helps to test services in a larger context and therefore brings the tests closer to the real world.
This approach enables to develop system tests at unit test level as there is no need for running external systems such as a content server or a servlet engine. The basic idea is to use a Spring application context that is composed from the same Spring bean declaration files that are used in the project.
Note | |
---|---|
Note that this requires the project Spring bean declaration in general to be self-contained and independent from each other. Otherwise, the application context could become too unhandy for testing when too many declarations have to be included recursively. |
The add-on provided by CoreMedia supports an easy and convenient setup of an application context providing especially an in-memory content repository for your tests.
Below you will find two examples. For more examples, usage information and templates you might want to use in your IDE have a look at XmlRepoConfiguration.
Examples
Testing Link Schemes
This example demonstrates how to set up an infrastructure that can be used for testing project
link schemes. In the project's bean declaration
myproject-linkschemes-beans.xml
several link schemes are defined, as
well as some CAE basic infrastructure such as the LinkFormatter bean. It is very useful to load
exactly this file into a test application context, in order to...
test the contents of the file itself, for example detect whether there a syntactical or wiring problems
test the service instances with a configuration that is (nearly) equal to the configuration used in the project
test the service (in this example: the links scheme) in interaction with similar services, for example make sure that a certain link scheme is addressed for certain parameters and not a different link scheme instance.
Use the configuration pattern to construct the application context with the desired configuration:
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = MyTest.LocalConfig.class) @ActiveProfiles(MyTest.LocalConfig.PROFILE) public class MyTest { @Configuration @ImportResource( value = { XmlRepoResources.LINK_FORMATTER, "classpath:/com/mycompany" + "/myproject/myproject-linkschemes-beans.xml" }, reader = ResourceAwareXmlBeanDefinitionReader.class ) @Import(XmlRepoConfiguration.class) @Profile(PROFILE) public static class LocalConfig { public static final String PROFILE = "MyTest"; } // ... }
Using a local test-only profile is recommended if you are using component scan to find your beans.
If not using the ActiveProfile
, Profile
annotation pair
LocalConfig
classes of other tests might be found through component scan.
Now you can just inject the LinkFormatter
and use it as in production code:
@Inject LinkFormatter linkFormatter; String link = linkFormatter.formatLink( new MyPage(123), "myView", new MockHttpServletRequest(), new MockHttpServletResponse(), false); Assert.assertEquals("/123?view=myView", link);
Testing Handlers
A controller/handler's behavior strongly depends on the concrete setup of the application
context. For instance, the registered Converters
or PropertyEditors
might have an influence on its behavior as well as the currently used
HandlerMapping
. Thus, it might be useful to take this environment into account when
testing a handler. Spring provides MockMvc
for emulating servlet
requests and by capturing a handler's ModelAndView
result. See corresponding
JavaDoc for details.
@RunWith(SpringJUnit4ClassRunner.class) @WebAppConfiguration @ContextConfiguration(classes = MyTest.LocalConfig.class) @ActiveProfiles(MyTest.LocalConfig.PROFILE) public class MyTest { @Configuration @ImportResource( value = { XmlRepoResources.HANDLERS, "classpath:/com/mycompany" + "/myproject/myproject-handlers-beans.xml" }, reader = ResourceAwareXmlBeanDefinitionReader.class ) @Import(XmlRepoConfiguration.class) @Profile(LocalConfig.PROFILE) public static class LocalConfig { public static final String PROFILE = "MyTest"; @Bean @Scope(SCOPE_SINGLETON) MockMvc mockMvc(WebApplicationContext wac) { return MockMvcBuilders.webAppContextSetup(wac).build(); } } @Inject private MockMvc mockMvc; @Test public void test() throws Exception { Object expectedModelBean =...; mockMvc .perform( MockMvcRequestBuilders .get("/context/servlet/123") .servletPath("/servlet") .contextPath("/context") ) .andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers .model() .attribute( HandlerHelper.MODEL_ROOT, Matchers.equalTo(expectedModelBean) ) ); } }
Mind the test annotation @WebAppConfiguration
which is required to have a
WebApplicationContext
available to build the MockMvc
object.
MockMvcResultMatchers
provides several matchers for validating the response. For
more sophisticated analysis you can end the validation with andReturn()
and get for
example the ModelAndView
from the returned MvcResult
.
More information
Take a look at the Javadoc of XmlRepoConfiguration for getting more examples and how to use for example a custom in memory content repository.