Junit 3 vs Junit 4 Overview

Junit 4 is the next series of Junit 3 and introduced lot of features. It has been compatible with most tools for a while. We will compare junit 3 and junit 4 to give the difference from 11 aspects.

1. JDK Required?

JUnit 4 requires Java 5 or higher, it uses a lot from Java 5 annotations, generics, and static import features. The JUnit 3.x version can work with JDK 1.2+ and any higher versions.

2. JPackage Structure

JUnit 4 is built on the idea of backward compatibility, it leaves the old package org.junit. For all JUnit 4.x new features, they were added to a new package junit.framework.

3. How to define a text case? Junit 3 VS Junit 4

In the new version of JUnit, test classes are no longer required to extend junit.framework.TestCase class, test names are no longer need required to follow the testXXX pattern. Instead, in Junit4.x, any public classes with a zero-argument public constructor can act as a test class, any methods which need  consider as a test method should be annotated with the @Test annotation.

A typical test case in Junit 3.x

TournamentTest.java
import junit.framework.Assert;
import junit.framework.TestCase;

public class TournamentTest extends TestCase{
  Tournament tournament;

  public void setUp() throws Exception {
    System.out.println("Setting up ...");
    tournament = new Tournament(100, 60);
  }

  public void tearDown() throws Exception {
    System.out.println("Tearing down ...");
    tournament = null;
  }

  public void testGetBestTeam() {
    Assert.assertNotNull(tournament);

    Team team = tournament.getBestTeam();
    Assert.assertNotNull(team);
    Assert.assertEquals(team.getName(), "Test1");
  }
}

A typical test case in Junit 4.x

TournamentTest.java
import junit.framework.Assert;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

public class TournamentTest {
  Tournament tournament;

  @Before
  public void init() throws Exception {
    System.out.println("Setting up ...");
    tournament = new Tournament(100, 60);
  }

  @After
  public void destroy() throws Exception {
    System.out.println("Tearing down ...");
    tournament = null;
  }

  @Test
  public void testGetBestTeam() {
    Assert.assertNotNull(tournament);

    Team team = tournament.getBestTeam();
    Assert.assertNotNull(team);
    Assert.assertEquals(team.getName(), "Test1");
  }
}

4. Annotations and new features added (Junit 3 VS Junit 4).

In JUnit 3.x, we have to override the setUp() and tearDown() methods. But in,JUnit 4.x, it is based on annotations, it would not require to extend any particular methods, use @Before and @After to annotate the methods which needs execution right before/after each of the tests. Another new feature that JUnit 4.x offers is the @BeforeClass and @AfterClass annotations. the methods with this annotations are executed before/after a whole set of tests.

Feature JUnit 3.x JUnit 4.x
test annotation testXXX pattern @Test
run before the first test method in the current class is invoked None @BeforeClass
run after all the test methods in the current class have been run None @AfterClass
run before each test method override setUp() @Before
run after each test method override tearDown() @After
ignore test Comment out or remove code @ignore
expected exception catch exception assert success @Test(expected = ArithmeticException.class)
timeout None @Test(timeout = 1000)

5. New JUnit runners

The 3.x version of JUnit comes with Swing and AWT test runners that are no longer part of the JUnit distribution. The test runner façade that you can use to start your tests from the console is now called org.junit.JUnitCore.

6. Static imports, New assertions and assumptions.

Junit3.x lacks the ability of  comparing equality of arrays and assumptions. In Junit 4, it introduced more interesting and valuable assert method (see below), you can also easily import all assertion methods or any particular one.

assertEquals(Object[] expected, Object[] actual)
assertEquals(String message, Object[] expected, Object[] actual)
assumeThat(T actual, org.hamcrest.Matcher<T> matcher)

7. Exception testing (Difference between Junit 3 and Junit 4)

in Junit 4.x, @expected was added to test exceptional situations in your code.

Junit 3.x

Test case: testGetElement
public void testGetElement() {
  try {
    (new ArrayList()).get(0);
    fail("The test should have failed");
  } catch (NullPointerException e) {
    assertTrue("Sanity check", true);
  }
}

Junit 4.x

@Test(expected = IndexOutOfBoundsException.class)
public void testGetElement() {
  (new ArrayList()).get(0);
}

8. Ignoring a test

In the 3.x version of JUnit, the only way to do that is to comment the whole test method or rename the method. This is significantly improved in JUnit 4.x, by the introduction of the @Ignore annotation.

9. Timeout testing

Another parameter you can add to the @Test annotation is the timeout parameter.This feature was also missing in the “old” JUnit. With this parameter, you can specify a value in milliseconds that you expect to be the upper limit of the time you spend executing your test.

10. Test suites

The old way of constructing sets of your tests involved writing a suite() method and manually inserting all the tests that you want to be present in the suite. Because the new version of JUnit is annotation oriented, it seems somehow logical that the construction of suites is also done by means of annotation. Further, the suite construction is done not by one annotation but by two annotations: the @RunWith and @Suite Classes annotations. The first annotation lets you define test runners that you can use to run your tests. The @RunWith annotation accepts a parameter called value, where you need to specify the test runner to run your suite: Suite.class. This test runner is included with JUnit, along with some other runners. But in this annotation you can also specify a custom runner.  The second annotation declares all the tests that you want to include in the suite. You list the classes that hold your tests in the value parameter of the @SuiteClasses annotation.

11. Parameterized tests

As you saw, in Junit 4.x, the @RunWith annotation lets you define a test runner to use. The Suite test runner that we already presented lets you run your test cases in a suite. Another test runner that’s bundled with the JUnit distribution is the Parameterized test runner. This test runner lets you run the same tests with different input test data.

Conclusion

JUnit 4 has lots of advantages over 3.x,  most tools have been compatible with 4.x for a while now. I think we have no reason that stick to 3.x.