Well we finally got around to upgrade all our unit tests to new features. About time really!
We use maven and the maven-surefire-plugin for running our unit tests during our build process. Let’s look at the steps I did to get migrate.
- All our test cases extend from a single abstract test case class called AbstractLiveTestCase that in our Junit 3 integration extended from junit.framework.TestCase. For Junit 4, tests are described with annotations so we don’t need to extend this class anymore – so I (1) removed the “extends TestCase” from our AbstractLiveTestCase
- The Junit 3 TestClass class used to provide all the handy assert functions. These are now provided as org.junit.Assert static methods so I went through each of our tests and (2) added “import static org.junit.Assert.*;” to the top of each class. With the handing auto source code formatting in Eclipse enabled, Eclipse automatically expanded the “org.junit.Assert.*” imports to the explicit ones needed for that class when I saved it.
- And finally (3) Added @Test to each test method so that Junit would know what tests to run.
Basically that was it – surefire/maven/junit picked up the test cases in the new style – and in most cases that’s job done. However we wanted to go a little further.
We had also implemented in Junit 3 a handy feature that outputted a quick ERROR message in the system out of a test run so we could quickly see the failure. By default maven’s surefire simply tells you there was a failure, but you have to look at a file to see what it was. Bit of pain that, so in our Junit 3 extension we would provide more info on the screen when a failure occurred, for example we might see something like:
Running com.bemoko.live.platform.mwc.sites.LiveSiteTestCase
ERROR : *** Test Failure *** Site home not correct expected: but was: @ line 17 of com.bemoko.live.platform.mwc.sites.LiveSiteTestCase (com.bemoko.live.platform.BemokoTestListener)
Tests run: 1, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 0.01 sec <<< FAILURE!
In Junit 3 we did this by overriding the runTest method of the TestCase class. In Junit 4 we can use runners and listeners. To start with we set the @RunWith annotation on our AbstractLiveTestCase to indicate that all of our tests should run with a specified runner …
@RunWith(BemokoTestRunner.class) public abstract class AbstractLiveTestCase {
The runner was defined to register a listener …
1 2 3 4 5 6 7 8 9 10 | public class BemokoTestRunner extends BlockJUnit4ClassRunner { public BemokoTestRunner(Class<?> clazz) throws InitializationError { super(clazz); } @Override public void run(final RunNotifier notifier) { notifier.addListener(new BemokoTestListener()); super.run(notifier); } } |
and the listener was defined to listen for failures …
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | public class BemokoTestListener extends RunListener { private static Log log = LogFactory.getLog(BemokoTestListener.class); @Override public void testFailure(Failure failure) { Throwable t = failure.getException(); if (t instanceof Exception) { log.error("*** Test Failure *** " + t.getMessage(), t); } else { if (t.getMessage() != null) { log.error("*** Test Failure *** " + t.getMessage() + " @ " + getErrorLocation(t.getStackTrace())); } else { log.error("*** Test Failure *** ", t); } } } @Override public void testIgnored(Description description) { if (log.isWarnEnabled()) { log.warn("+++ Test ignored +++ " + description.getDisplayName()); } } private String getErrorLocation(StackTraceElement[] st) { for (StackTraceElement ste : st) { if (ste.getClassName().startsWith("com.bemoko") && !ste.getClassName().contains("AbstractLiveTestCase")) { return "line " + ste.getLineNumber() + " of " + ste.getClassName(); } } return "(line number and class not known)"; } } |
in this way I can handle events from my tests in any way I see fit and much more elegant that the Junit 3 implementation I previously had.
Job done and we’re all sorted for our unit test framework for the foreseeable future.

Hi,
Really useful little technique for logging test results. Thanks