Category Archives: testing

JMockit jar loading from remote file systems enabled

Over the past few months we’ve faced significant hurdles integrating jmockit into our development environment at a client-site primarily but not entirely because it is not a conventional development environment. The most noteable of these has been the inability to load the jmockit jar file from a mounted drive which is a remote file system. Having remote paths in the classpath such as //foo/bar/baz/jmockit.jar would result in a java.net.URI being constructed with that remote path and the URI being passed to the following java.io.File constructor.

public File(URI uri) {
    if (!uri.isAbsolute())
        throw new IllegalArgumentException("URI is not absolute");
    if (uri.isOpaque())
        throw new IllegalArgumentException("URI is not hierarchical");
    String scheme = uri.getScheme();
    if ((scheme == null) || !scheme.equalsIgnoreCase("file"))
        throw new IllegalArgumentException("URI scheme is not "file"");
    if (uri.getAuthority() != null)
        throw new IllegalArgumentException("URI has an authority component");
    if (uri.getFragment() != null)
        throw new IllegalArgumentException("URI has a fragment component");
    if (uri.getQuery() != null)
        throw new IllegalArgumentException("URI has a query component");
    String p = uri.getPath();
    if (p.equals(""))
        throw new IllegalArgumentException("URI path component is empty");
    p = fs.fromURIPath(p);
    if (File.separatorChar != '/')
        p = p.replace('/', File.separatorChar);
    this.path = fs.normalize(p);
    this.prefixLength = fs.prefixLength(this.path);
}

The following snippet in the above code would then result in an IllegalArgumentException being thrown with the message URI has an authority component and of course the authority component would be //foo.

if (uri.getAuthority() != null)
    throw new IllegalArgumentException("URI has an authority component");

This morning, however, I happened to notice the following extract in the jmockit changelog for the latest preview version – 0.997 although I’m not sure how long ago this was done.

A few fixes and enhancements to JMockit’s internal auto-initialization mechanisms: jmockit.jar (or a versioned jar name) can now be loaded from a remote file system without triggering a security-related exception

I wonder if this was in response to Shankar’s post on the obstacles we faced. It remains to be seen whether this indeed refers to the above issue and whether it resolves it. I’ll try it out once this version is finally released. Just for the record, to place renewed emphasis on the points made in Shankar’s article, the changes outlined in the following changelog entry under version 0.993 have caused us integration difficulties also.

Enhancement: to make JMockit easier to use when running under JDK 1.6+ without the -javaagent JVM parameter, two simplifications were introduced:

  • The /lib/tools.jar file no longer needs to be added to classpath.
  • Test classes no longer need to be annotated with @RunWith(JMockit.class) (for JUnit 4 tests), nor extend a JUnit/TestNG integration base class (JMockitTest, JMockitTestCase, JMockitTestNG).

There is a requirement for the second item when using JUnit, though: jmockit.jar needs to come before junit-4.x.jar in the classpath.

The above changes placed a constraint on classpath ordering and, by default, loaded all tests using the jmockit junit runner rather than the original junit runner and if jmockit wasn’t properly initialised then all tests would fail as long as jmockit was on the classpath. It’s a tricky problem to approach for jmockit. Making life easier for certain environments makes it more difficult in others. I would say that jmockit should allow the user to define how they would like their agent loaded and also have jmockit enabled explicitly only and not behind the scenes. Once integrated, however, it is a fine mocking library with a unique feature set.

JMockit: No holds barred testing with instrumentation over mocking

Introduction

The transition from junit to stubs to mocking occurred long back in the world of testing. Traditionally mocking has used jdk proxies for interface based classes and cglib for non-final concrete classes. This article draws attention to the yet ongoing transition from mocking to instrumentation for testing. Particularly it highlights how to achieve complete access to your API by being able to instrument and thereby mock areas of your code that were previously inaccessible.

In exploring this it becomes evident that testing as it stood prior to instrumentation required one to alter the design of production code fundamentally to accommodate testing. Prime examples of such practices have been the non-production related use of interfaces, widening the visibility of methods and not using the final and static keywords. Conversely the practices of overusing dependency injection, interfaces and instance based state, all for testing, have become all too common and established under the purported benefit that they make code more testable.

Examples

A clear delineation between production code and testing code finally becomes possible with JMockit which uses the java.lang.instrument package of JDK5 and ASM to modify bytecode at runtime and thereby has access to all regions that are accessible in the bytecode itself.

The following sections illustrate the most powerful features of JMockit that distinguish it from proxy based mocking tools with each code example being self contained and runnable – complete with imports. In each case the test subject API is contained within the test case itself for ease of reference and not having to switch back and forth. All source code is also available as a self contained eclipse maven project. Update [11/11/2009]: This download now has all fixes and enhancements to code and maven pom file suggested by, Rogério Liesenfeld, the author of JMockit.

The term ‘mocking’ is used here loosely to refer to mocking through instrumentation as it is common vocabulary. Strictly speaking, however, there is a distinction between mocking which creates a second instance of the test subject and instrumentation which mostly modifies or redefines the original test subject. However, here, these terms will be used interchangeably. Also please excuse the slight contrived and convoluted nature of the test subject API.

Mock classes that don’t implement interfaces

Classes that don’t implement interfaces cannot be mocked using jdk proxies and generally have to be deferred to cglib for subclassing. In this case neither is necessary. Here the @RunWith annotation loads the javaagent contained in jmockit.jar through the entry point of JMockit.class into the JVM prior to the testcase running. The @Mocked annotation designates which classes you’d like instrumented. The Expectations block encloses the specifications of how you’d like your classes instrumented. The end result is that the user name of ‘joe’ is replaced with ‘fred’.

package jmockit.examples;

import static org.junit.Assert.assertEquals;
import mockit.Expectations;
import mockit.Mocked;
import mockit.integration.junit4.JMockit;

import org.junit.Test;
import org.junit.runner.RunWith;

@RunWith(JMockit.class)
public class MockNoInterfaceClassTest {

    static class User {
        String name() {
            return "joe";
        }
    }

    @Mocked
    User user;

    @Test
    public void mockNoInterfaceFinalClass() {

        new Expectations() {
            {
                user.name();
                returns("fred");
            }
        };

        assertEquals("fred", user.name());

    }
    
}

Mock final classes and methods

As no proxying is done JMockit is able to modify the bytecode of the test subject without needing to subclass the subject.

package jmockit.examples;

import static org.junit.Assert.assertEquals;
import mockit.Expectations;
import mockit.Mocked;
import mockit.integration.junit4.JMockit;

import org.junit.Test;
import org.junit.runner.RunWith;

@RunWith(JMockit.class)
public class MockFinalClassTest {

    static final class User {
        final String name() {
            return "joe";
        }
    }

    @Mocked
    User user;

    @Test
    public void mockFinalClass() {

        new Expectations() {
            {
                user.name();
                returns("fred");
            }
        };

        assertEquals("fred", user.name());

    }
    
}

Mock internal (hidden) instantiations

The User might have a dependency on Address and as illustrated below neither the User nor the test class may have access what the Address is doing. This is referred to here as an internal or hidden invocation or instantiation. Since only the behaviour of Address is of any interest then only that class is marked for instrumentation. Note particularly that no dependency injection of any kind is necessary to make this code testable. JMockit can instrument internally managed dependencies.


package jmockit.examples;

import static org.junit.Assert.assertEquals;
import mockit.Expectations;
import mockit.Mocked;
import mockit.integration.junit4.JMockit;

import org.junit.Test;
import org.junit.runner.RunWith;

@RunWith(JMockit.class)
public class MockInternalInstantiationTest {

    static class User {
        Address address() {
            return new Address();
        }
    }

    static class Address {
        String postCode() {
            return "sw1";
        }
    }

    @Mocked
    Address address;

    @Test
    public void mockInternalInstantiation() {

        new Expectations() {
            {
                new Address().postCode();
                returns("w14");
            }
        };

        String postCode = new User().address().postCode();
        assertEquals("w14", postCode);

    }
    
}

Mock static methods

Static methods can be instrumented in jmockit in exactly the same way as instance methods.

package jmockit.examples;

import static org.junit.Assert.assertEquals;
import mockit.Expectations;
import mockit.Mocked;
import mockit.integration.junit4.JMockit;

import org.junit.Test;
import org.junit.runner.RunWith;

@RunWith(JMockit.class)
public class MockStaticMethodTest {

    static class User {
        static String name() {
            return "joe";
        }
    }

    @Mocked
    @SuppressWarnings("unused")
    private final User user = null;

    @Test
    public void mockStaticMethod() {

        new Expectations() {
            {
                User.name();
                returns("fred");
            }
        };

        assertEquals("fred", User.name());

    }

}

Mock native methods

Being able to alter the behaviour of native methods is one of the most powerful features of JMockit. Frequently native code isn’t mockable in the traditional way due to being final or static. However in the example below the JMockit API provides a means of substituting the original native method with one that you define. The end result here is that Runtime.getRuntime().availableProcessors() returns 999. That’s a far cheaper way to approximate Azul.

package jmockit.examples;

import static org.junit.Assert.assertEquals;
import mockit.Mock;
import mockit.MockUp;
import mockit.integration.junit4.JMockit;

import org.junit.Test;
import org.junit.runner.RunWith;

@RunWith(JMockit.class)
public class MockNativeMethodTest {

    @Test
    public void mockNativeMethod() {
        new MockUp<Runtime>() {
            @Mock
            @SuppressWarnings("unused")
            int availableProcessors() {
                return 999;
            }
        };
        assertEquals(999, Runtime.getRuntime().availableProcessors());
    }

}

Mock private methods

Private methods are instrumentable through reflection based utilities provided by JMockit. Here the user name is a private field with no mutator methods to alter it. It is also a final field. Note that despite all that the Expectations block is able to modify the field, record an expected invocation of the accessor method and specify a return value for it. Although the API is slightly different than what it is for visible methods nevertheless it is concise and intuitive.

package jmockit.examples;

import static org.junit.Assert.assertEquals;
import mockit.Deencapsulation;
import mockit.Expectations;
import mockit.Mocked;
import mockit.NonStrict;
import mockit.integration.junit4.JMockit;

import org.junit.Test;
import org.junit.runner.RunWith;

@RunWith(JMockit.class)
public class MockPrivateMethodTest {

    static class User {

        private final String name = "joe";

        @SuppressWarnings("unused")
        private final String name() {
            return name;
        }

    }

    @Mocked
    @NonStrict
    User user;

    @Test
    public void mockPrivateMethod() {
        new Expectations() {
            {
                invoke(user, "name");
                returns("fred");
            }
        };
        assertEquals("fred", Deencapsulation.invoke(user, "name"));
    }

}

Mock default constructors

Here the default constructor of an object is substituted by a constructor specified in the test case itself. The only additional API necessary here is the registration of the new constructor body with JMockit in the beforeClass() method prior to the test case running. The new constructor body is denoted by a special method name called $init which is named after its form in the class file.

package jmockit.examples;

import static org.junit.Assert.assertEquals;

@RunWith(JMockit.class)
public class MockDefaultConstructorTest {

    static class User {

        String name;

        public User() {
            this.name = "joe";
        }

        String name() {
            return name;
        }

    }

    private static final User user = new User();

    @Test
    public void mockDefaultConstructor() {
        new MockUp<User>() {
            @Mock
            @SuppressWarnings("unused")
            public void $init() {
                user.name = "fred";
            }
        };
        new User();
        assertEquals("fred", user.name());
    }

}

Mock static initialiser blocks

In the same way as constructors can be redefined so can static initialiser blocks. The only difference is that the new static initialiser block must be represented by a method called $clinit which again is named after its form in the class file after the jvm has compacted all static initialiser blocks into one block.

package jmockit.examples;

import static org.junit.Assert.assertEquals;
import mockit.Mock;
import mockit.MockUp;
import mockit.integration.junit4.JMockit;

import org.junit.Test;
import org.junit.runner.RunWith;

@RunWith(JMockit.class)
public class MockStaticInitialiserBlockTest {

    static class UserInitialiser {
        static {
            User.name("joe");
        }
    }

    static class User {

        private static String name;

        static void name(String name) {
            User.name = name;
        }

    }

    @Test
    public void mockStaticInitialiserBlock() throws ClassNotFoundException {
        new MockUp<UserInitialiser>() {
            @Mock
            @SuppressWarnings("unused")
            public void $clinit() {
                User.name("fred");
            }
        };
        Class.forName(UserInitialiser.class.getName());
        assertEquals("fred", User.name);
    }

}

Verify internal (hidden) method invocations

Verifications can be an untuitive and confusing concept to grasp so here is a brief account of the jmockit test run lifecycle. The Expectations block puts in place the record phase. Once that block has ended it automatically switches to replay phase. The execution phase is the test subject API invocations themselves. So where do the verifications fit in? Well if Expectations can be thought of as the pre-expectations then verifications are post-expectations. However note that verifications can only complete those expectations that haven’t already been recorded in the Expectations block.

In the example below the creation and population of the User pojo is entirely hidden. So the testcase has no pre-expectations of return values or exceptions being thrown. The only thing the test case would like to verify is that the User was populated through specific method invocations in a given order with a specified set of arguments. The Verifications block verifies exactly that although one can also have optional verifications that are in any order with arguments matching supplied patterns. Note that in the verification of the setName() method the test case specifies that the method invocation must have taken place with an argument of exactly ‘fred’. However with setAge() it specifies only that the method should have been invoked with any integer. These are hamcrest matchers and are add incredible leeway in specifying invocation criteria.

package jmockit.examples;

import mockit.FullVerificationsInOrder;
import mockit.Mocked;
import mockit.integration.junit4.JMockit;

import org.junit.Test;
import org.junit.runner.RunWith;

@RunWith(JMockit.class)
public class VerifyInternalMethodsTest {

    static class User {

        String name;
        int age;

        public void setName(String name) {
            this.name = name;
        }

        public void setAge(int age) {
            this.age = age;
        }

    }

    static class UserService {

        void populateUser() {
            User user = new User();
            user.setName("fred");
            user.setAge(31);
        }
    }

    @Mocked
    User user;

    @Test
    public void verifyInternalMethods() {
        new UserService().populateUser();
        new FullVerificationsInOrder() {
            {
                User user = new User();
                user.setName("fred");
                user.setAge(withAny(1));
            }
        };

    }

}

Mock method invokes real method

Here the mock method is invoking the real method in the test subject. JMockit allows a special ‘it’ instance variable in a mock class that is set to the real class instance for each indirect call to a mock method. Unusual and interesting although it’s not immediately obvious why one might use this feature. It is also disabled by default as it can potentially result in stack overflow due to each calling the other in an infinite recursive loop.

package jmockit.examples;

import static org.junit.Assert.assertEquals;
import mockit.Expectations;
import mockit.Mock;
import mockit.MockClass;
import mockit.Mockit;
import mockit.integration.junit4.JMockit;

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

@RunWith(JMockit.class)
public class MockInvokesRealMethodTest {

    static class User {
        String name() {
            return "joe";
        }
    }

    @MockClass(realClass = User.class)
    static class MockUser {
        User it;

        @Mock(reentrant = true)
        String name() {
            return it.name();
        }
    }

    @BeforeClass
    public static void beforeClass() {
        Mockit.setUpMocks(MockUser.class);
    }

    @AfterClass
    public static void afterClass() {
        Mockit.tearDownMocks();
    }

    @Test
    public void mockInvokesRealMethod() {

        new Expectations() {
            {
                new User().name();
            }
        };

        assertEquals("joe", new User().name());
    }

}

Mock JDK randomness

Ultimately the power of JMockit is used to mutate certain JDK methods that otherwise are inaccessible and behave very differently! This is done to show that the reach of JMockit extends even to the most diverse behaviours in the JDK and also of course for amusement and intrigue.

package jmockit.examples;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertSame;

import java.security.SecureRandom;

import mockit.Expectations;
import mockit.Mock;
import mockit.MockUp;
import mockit.Mocked;
import mockit.integration.junit4.JMockit;

import org.junit.Test;
import org.junit.runner.RunWith;

@RunWith(JMockit.class)
public class MockJdkRandomnessTest {

    @Test
    public void mockSystemNanoTime() {
        new MockUp<System>() {
            @Mock
            @SuppressWarnings("unused")
            long nanoTime() {
                return 0L;
            }
        };
        assertSame(0L, System.nanoTime());
    }

    @Test
    public void mockMathRandom() {
        new MockUp<Math>() {
            @Mock
            @SuppressWarnings("unused")
            double random() {
                return 0D;
            }
        };
        assertEquals(0D, Math.random(), 0D);
    }

    @Mocked
    SecureRandom secureRandom;

    @Test
    public void mockSecureRandom() {

        new Expectations() {
            {
                new SecureRandom().nextInt();
                returns(0);
            }
        };
        assertSame(0, new SecureRandom().nextInt());
    }

}

Conclusion

JMockit, by way of instrumentation, creates a new genre of testing toolkit that exposes the fundamental limitations and weaknesses in the preceding genre of traditional mocking tools. Critically, the design of production code, should remain unaffected by testing of that code. Interfaces should only be used when felt necessary for production code and there should be no penalty for using the final or static keywords or other language features. By operating at a lower level of abstraction and at a different stage of the VM lifecycle JMockit is able to reinstate the use of the language in its entirety*.

*There’s one language feature which JMockit does not support due to the fact that it is not distinctly supported in the bytecode itself. This is left as a quiz for the reader. 10 points to the first winner. Sorry – points are all I have to give.

Download

All source code above is available as a self contained eclipse maven project. Update [11/11/2009]: This download now has all fixes and enhancements to code and maven pom file suggested by, Rogério Liesenfeld, the author of JMockit.

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.