Tag Archives: junit

Using MockServletContext and ContextLoader with Spring 2.5 TestContext framework

Other than being, quite possibly, the longest blog post title so far here this topic had recently been a thorn in my side at work. Here I present the problem and a few different solutions to it. I’ve noticed also that on the spring forum a few others have been asking the same question so I hope this helps them too. Please note that code examples are deliberately kept as short as is necessary to illustrate the solutions. If adopting these solutions you may want to enhance the API yourself. Prior to stating the problem imagine the following ant based web application directory structure.

Project directory structure

project/
|-- java
`-- tests
|-- webapp
|   `-- WEB-INF
|       |-- bar-context.xml
|       |-- foo-context.xml
|       |-- classes
|       `-- lib

The Problem

The problem was to create a base class for spring integration tests that recognised the mock servlet context when loading spring context files and resources. Being a webapp the problem specification required that all paths to spring context files and resources must be relative to the web root (in this case ‘webapp/’) and should therefore start with ‘/WEB-INF/blah’. Also I wanted to do this using the new Spring 2.5 TestContext framework and JUnit4 so that I could use their improved APIs to make life easier and also because I didn’t want to base all tests written in the future on outdated api and versions.

Spring 2.0 and JUnit 3 Solution

import junit.framework.TestCase;

import org.springframework.core.io.FileSystemResourceLoader;
import org.springframework.mock.web.MockServletContext;
import org.springframework.web.context.ConfigurableWebApplicationContext;
import org.springframework.web.context.support.XmlWebApplicationContext;

public abstract class AbstractJUnit3SpringIntegrationTest extends TestCase {

    protected static ConfigurableWebApplicationContext context;

    @Override
    protected void setUp() throws Exception {
        context = new XmlWebApplicationContext();
        context.setConfigLocations(new String[] { "/WEB-INF/foo-context.xml", "/WEB-INF/bar-context.xml" });
        context.setServletContext(new MockServletContext("/webapp", new FileSystemResourceLoader()));
        context.refresh();
        context.registerShutdownHook();
    }

    @Override
    protected void tearDown() throws Exception {
        context.close();
    }

    protected Object getBean(String beanName) {
        return context.getBean(beanName);
    }

}

Note that the above could be enhanced if necessary by allowing the child classes to specify the context file locations that they require and also by provided a strong typed generified getBean() method which would remove the need for casting from Object on every invocation. It is also possible to make the setup and teardown happen once only per class if desired. See elsewhere on this site for sample code.

Spring 2.0 and JUnit 4 Solution

import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.springframework.core.io.FileSystemResourceLoader;
import org.springframework.mock.web.MockServletContext;
import org.springframework.web.context.ConfigurableWebApplicationContext;
import org.springframework.web.context.support.XmlWebApplicationContext;

public abstract class AbstractJunit4SpringIntegrationTest {

    protected static ConfigurableWebApplicationContext context;

    @BeforeClass
    public static void setUpBeforeClass() throws Exception {

        String[] contexts = new String[] { "/WEB-INF/foo-context.xml" };
        context = new XmlWebApplicationContext();
        context.setConfigLocations(contexts);
        context.setServletContext(new MockServletContext("/webapp", new FileSystemResourceLoader()));
        context.refresh();

    }

    @AfterClass
    public static void tearDownAfterClass() {
        context.close();
    }

    protected Object getBean(String beanName) {
        return context.getBean(beanName);



    }

}

The difference with junit4 is that no inheritance is required and the context setup and teardown is done only once at the beginning and end respectively. The same suggestions for enhancement apply here as before.

Spring 2.5 and JUnit 4 Solution

There were a number of choices to make when implementing this using Spring 2.5 TestContext framework and JUnit 4. I will refer to the Spring 2.5 TestContext framework as TCF to relieve RSI somewhat. TCF API or documentation does not really offer a way of solving this problem out of the box. However by using lower level building blocks it is possible to achieve the desired effect. Let us look at how TCF works normally in the vanilla fashion.

import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "/WEB-INF/foo-context.xml", "/WEB-INF/foo-context.xml" })
public abstract class AbstractSpringTCFTest {
}

Of course that won’t work because /WEB-INF is not on the classpath and a mock servlet context has not been registered. The following example shows how this can be done. The abstract spring base class needs a custom context loader applied to it.

import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(loader = MockServletContextWebContextLoader.class, locations = {
        "/WEB-INF/foo-context.xml", "/WEB-INF/bar-context.xml" })
public abstract class AbstractSpringTCFTest {
}

The custom context loader is what sets a mock servlet context but also resolves certain api type compatibility issues. The key lines of code are highlighted below (which you won’t see if reading through rss).

import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotationConfigUtils;
import org.springframework.core.io.FileSystemResourceLoader;
import org.springframework.mock.web.MockServletContext;
import org.springframework.test.context.support.AbstractContextLoader;
import org.springframework.web.context.support.XmlWebApplicationContext;

public class MockServletContextWebContextLoader extends AbstractContextLoader {

    @Override
    public final ConfigurableApplicationContext loadContext(String... locations) throws Exception {
        ConfigurableWebApplicationContext context = new XmlWebApplicationContext();
        context.setServletContext(new MockServletContext("/webapp", new FileSystemResourceLoader()));
        context.setConfigLocations(locations);
        context.refresh();
        AnnotationConfigUtils.registerAnnotationConfigProcessors((BeanDefinitionRegistry) context.getBeanFactory());
        context.registerShutdownHook();
        return context;
    }

    @Override
    protected String getResourceSuffix() {
        return "-context.xml";
    }

}

So there we have it – the final solution using Spring 2.5 TCF and JUnit 4. I’ll be adding further enhancements and simplifications at a later date. Of course none of this hackery would be necessary if we were simply using classpath based resources. Classpath based access allows a uniform way of accessing resources of any kind through spring in any environment whether that be ant, eclipse or container. The spring resource locator types: classpath: and classpath*: will find items on the classpath with the latter asterisk based syntax searching for all matches on the filesystem including inside jars.

Update1: It turns out that there is a jira issue for this particular use case which is fantastic news and I believe we have Geoff, the commenter on this post, to thank for filing it. If you’d like to see this happen please add vote+comment to the jira issue. It is set to be completed by 3.0M2 which seems a little distant right now – it would have been great to have it in a point release. However better late than never.

Update2: Geoff please find my response below.

Originally the code in this post was implemented at my work place where it does work. However when I got around to trying it out in an isolated example project I too had the same problem – the lack of dependency injection and yes you can’t swap the refresh line and the annotations line due to a fatal exception.

Our work code base has extended certain spring classes to incorporate their own custom logic. So we are in fact using a custom subclass of XmlWebApplicationContext. However I did try using XmlWebApplicationContext and it still worked at work. As to why it works at my workplace and not in an isolated project I really haven’t had time to debug. However I think it’s great that this is finally filed as a jira which I’ve been meaning to do for quite some time because whether or not this problem can be solved with custom code I think that there should be native support for this in the spring framework. If I find out more about this issue I will post here and on forums to let you all know.

Update3: I’ve synchronised the minor differences between my work context loader and the example loader here (I’ve added the modifyLocations() method). Please retry and let me know. I’m unable to try this myself for the time being due to lack of time and a suitable environment.

Update4: Removed most recent modifications as they don’t work. It’s highly likely that this only works for me because at my workplace we are using a custom patched build of Spring and also our own classes which extend Spring (which I wasn’t aware of to this degree previously) so in order to get this work on a vanilla distribution please follow the forum link that GeoffM posted below or the jira ticket. Also vote on the jira ticket if you can. Thanks.

JUnit3, JUnit4 and Spring testing tips and trivia

If you’re in a legacy environment (as I am for the moment) with only the old version of junit at your disposal the following may be useful.

JUnit3 Multiple Instantiation [#]

import junit.framework.TestCase;

public class Junit3MultipleInstancesTest extends TestCase {

    public Junit3MultipleInstancesTest() {
        System.out.println("test instance created");
    }

    public void test1() {
        System.out.println("test1");
    }

    public void test2() {
        System.out.println("test2");
    }
    
}

What would you expect the above to print? Answer below.

test instance created
test instance created
test1
test2

JUnit4 Multiple Instantiation

import org.junit.Test;

public class Junit4MultipleInstancesTest {

    public Junit4MultipleInstancesTest() {
        System.out.println("test instance created");
    }

    @Test
    public void test1() {
        System.out.println("test1");
    }

    @Test
    public void test2() {
        System.out.println("test2");
    }

}

Output:

test instance created
test1
test instance created
test2

Would you want your test class to be instantiated on every test? Are you satisfied with the justification that it is done for complete test isolation between test methods? Does this make it impossible to maintain state between test methods without resorting to static context?

JUnit3 one time setup and one time teardown

Want to declare your one-time setup and one-time teardown in one place and reuse it for all your tests? You can.

Base class
import junit.framework.TestCase;

public class Junit3TestSuperClass extends TestCase {

    protected static void setUpBeforeClass() {
        System.out.println("set up before class");
    }

    protected static void tearDownAfterClass() {
        System.out.println("tear down after class");
    }

}
Child class
import junit.extensions.TestSetup;
import junit.framework.Test;
import junit.framework.TestSuite;

public class Junit3TestSubClass extends Junit3TestSuperClass {

    public static Test suite() {

        TestSuite suite = new TestSuite(Junit3TestSubClass.class);

        return new TestSetup(suite) {

            protected void setUp() {
                setUpBeforeClass();
            }

            protected void tearDown() {
                tearDownAfterClass();
            }
        };

    }

    public void test1() {
        System.out.println("test1");
    }

    public void test2() {
        System.out.println("test2");
    }

}

The subclass, when run, prints the following.

set up before class
test1
test2
tear down after class

Yes – the additional infrastructural suite() method in the subclass is nasty but then again junit3 makes no other provisions. This is made a hell of a lot nicer in juni4 with the allowance of @BeforeClass and @AfterClass annotations.

JUnit4 one time setup and one time teardown

import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;

public class Junit4Test {

    @BeforeClass
    public static void setUpBeforeClass() throws Exception {
        System.out.println("set up before class");
    }

    @AfterClass
    public static void tearDownAfterClass() throws Exception {
        System.out.println("tear down after class");
    }

    @Test
    public void test1() {
        System.out.println("test1");
    }

    @Test
    public void test2() {
        System.out.println("test2");
    }

}

Performance optimisation

When testing one might want to reduce overhead and run tests quickly. This may be because you have a lot of tests or because you are waiting on them repeatedly to verify that your code is working correctly as per the laws of test-driven development.

For unit tests time, overhead and waiting are not normally a problem as they are pretty succinct, quick and free of other dependencies i.e are isolated. However, integration tests need a whole other approach as they are end-to-end and often rely on environmental and infrastructual tools and at times human intervention to work satisfactorily.

Take the rather common use-case of a Spring integration test. Spring have gone out of their way to provide a fully featured test framework and numerous mock classes to make testing quick and easy. However if certain considerations are overlooked it can make your integration test suite significantly slower. Adhering to the following helps.

  • Use the Spring test framework and paradigms. Don’t reinvent the wheel. You will almost certainly end up with a more inferior solution. If there’s a quirk of your application which prevents you from using a Spring based testing architecture for your spring application sort it out. It’s often the least time consuming option and aids better long term maintainability.
  • Use the context cache. Load the context once and run many integration tests. Spring 2.0.x and 2.5.x have native support for this out of the box. However if you are loading the context manually one can still cache using the above one-time setup and teardown paradigm. If your tests are modifying the context or in Spring’s terminology dirtying the context then it has support for reloading after designated dirty actions.
  • Use test context files. In this way heavyweight beans can be replaced with lighter and simple alternatives if necessary. Mocks can be introduced and a more custom aggregation of context files can be achieved. Test contexts are not a “bad thing” – in fact I would argue that they are a “good thing” and a necessity depending on the application. Ultimately tests are not secondary – they are part of your application – if done correctly then almost half of your application. You want them to be maintainable and efficient.
  • Use stubs and mocks for when you cannot rely on your environment or for better isolation. A stub is a dummy class which implements the same theoretical interface api as the original class but does nothing. A mock is like a dynamic stub which can be told to adapt to a particular class interface and can be told what input to receive and how to react to it. Mocks can make slow end-to-end integration tests run almost instantly unless of course you really do need end-to-end testing.
  • Use default lazy initialisation/loading of spring beans so that you only load the bean dependencies of the beans you require and are testing. If certain specific beans like scheduled jobs are not referred to by any other bean and need to be eagerly loaded at context startup then explicitly mark them as eagerly loaded. This is the same mentality as in hibernate.
  • Designate different types of tests in different areas. Layer them by responsibility. Data layer tests, business layer tests, service layer tests and controller tests all have different responsibilities and should be separated. The advantages are that you can run each responsibility separately but also it hugely improves structuring and maintainability. If using a build tool or continuous integration you can also ask these tools to run specific test groups at given time intervals or to skip certain problematic or slow test groups.

Essential test attributes

Incidentally, InfoQ, had an excellent article on testing recently. Here’s what I extracted to be the key attributes of a good test from my point of view.

  • Automated
  • Environment independent (to extent possible)
  • Easy to run
  • Quick to run
  • Provides regression testing capability
  • Can be run repeatedly
  • Demonstrates use of api through example
  • Order independent

Ultimately one has to be realistic. True TDD i.e. tests before code is difficult to achieve in a commercial hard driven environment and most people don’t expect it nor expect to be doing it. However, tests should at least be written after the task is done. After all, without that, how do we know anything works at any moment in time?

Recently I’ve overheard people question what benefits junit4 and spring 2.5 test context framework provide over the old ways of doing things. My short answer would be huge benefits. If I get time I’ll do a summary post on this topic. For now here are Junit4‘s and Spring‘s official answer.