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.

One thought on “JUnit3, JUnit4 and Spring testing tips and trivia

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s