Skip to main content
blog title image

3 minute read - Java For Testers Java JUnit JUnit Examples

Junit 4 vs 5 - basic differences

Jun 23, 2020

There are many differences between JUnit 4 and 5, in terms of JUnit 5 having more capabilities and different ways of doing stuff.

But there are some very obvious differences between 4 and 5 in terms of: ignoring tests, running methods before and after methods and test classes, and exception asserting.

Explanation Video

Marking Tests as Ignored:

  • JUnit 4 uses @Ignore
  • JUnit 5 uses @Disabled

JUnit 4

    @Ignore("because if this ran it would fail")
    @Test
    public void anIgnoredDisabledTest(){
        Assert.assertFalse(true);
    }

JUnit 5

    @Disabled("because if this ran it would fail")
    @Test
    public void anIgnoredDisabledTest(){
        Assertions.assertFalse(true);
    }

Assertions are statically accessed from:

  • JUnit 4 uses Assert.
  • JUnit 5 uses Assertions.

JUnit 4

    @Test
    public void aTestMethodAssertingTrue(){
        Assert.assertTrue(true);
    }

JUnit 5

    @Test
    public void aTestMethodAssertingTrue(){
        Assertions.assertTrue(true);
    }

Assertion message position differs:

  • JUnit 4 assertion messages are the first argument
  • JUnit 5 assertion messages are the last argument

JUnit 4

    @Test
    public void aTestMethodAssertingWithMessage(){
        String expected = "bob";
        Assert.assertEquals("Because we always expect bob", expected, "bob");
    }

JUnit 5

    @Test
    public void aTestMethodAssertingWithMessage(){
        String expected = "bob";
        Assertions.assertEquals(expected, "bob", "Because we always expect bob");
    }

Annotations for running code before and after each method:

  • JUnit 4 uses @Before, and @After
  • JUnit 5 uses @BeforeEach, and @AfterEach

JUnit 4

    @Before
    public void runsBeforeEveryMethod(){
        System.out.println("Running a Test Method");
    }

    @After
    public void runsAfterEveryMethod(){
        System.out.println("Finished Running a Test Method");
    }

JUnit 5

    @BeforeEach
    public void runsBeforeEveryMethod(){
        System.out.println("Running a Test Method");
    }

    @AfterEach
    public void runsAfterEveryMethod(){
        System.out.println("Finished Running a Test Method");
    }

Annotations for running code before and after each class:

  • JUnit 4 uses @BeforeClass, and @AfterClass
  • JUnit 5 uses @BeforeAll, and @AfterAll

JUnit 4

    @BeforeClass
    public static void runsBeforeEverything(){
        System.out.println("Running a Test Class");
    }

    @AfterClass
    public static void runsAfterEverything(){
        System.out.println("Finished Running a Test Class");
    }

JUnit 5


    @BeforeAll
    public static void runsBeforeEverything(){
        System.out.println("Running a Test Class");
    }

    @AfterAll
    public static void runsAfterEverything(){
        System.out.println("Finished Running a Test Class");
    }

By default the methods need to be static in both JUnit 4 and 5, but in v5 we can annotate the class to avoid need to make the All methods static:

  • @TestInstance(TestInstance.Lifecycle.PER_CLASS)

Checking that an exception is thrown:

  • JUnit 4 uses @Test(expected = InterruptedException.class)
  • JUnit 5 uses an assertion with the code in a closure lambda expression, which allows additional assertions to be made on the exception
Exception exception = Assertions.assertThrows(RuntimeException.class, () -> {
    throw new NullPointerException(
                  "We interrupt this test to throw an runtime exception");
});

JUnit 4

    @Test(expected = IOException.class)
    public void shouldThrowAnCheckedException() throws IOException {
        throw new IOException(
                     "We interrupt this test to throw an checked exception");
    }

    @Test(expected = NullPointerException.class)
    public void shouldThrowAnRuntimeException(){
        throw new NullPointerException(
                     "We interrupt this test to throw an runtime exception");
    }

JUnit 5

    @Test
    public void shouldThrowAnCheckedException(){
        Exception exception = Assertions.assertThrows(IOException.class, () -> {
            throw new IOException(
                       "We interrupt this test to throw an checked exception");
        });

        // can continue to do more assertions on the exception
        System.out.println(exception.getMessage());
        Assertions.assertEquals(
                        "We interrupt this test to throw an checked exception",
                                exception.getMessage());
    }

    @Test
    public void shouldThrowAnRuntimeException(){
        Exception exception = Assertions.assertThrows(RuntimeException.class, () -> {
            throw new NullPointerException(
                         "We interrupt this test to throw an runtime exception");
        });

        // can continue to do more assertions on the exception
        System.out.println(exception.getMessage());
        Assertions.assertEquals("We interrupt this test to throw an runtime exception",
                exception.getMessage());
    }

Note: from JUnit 4.13 it is possible to use assertThrows in Junit 4 as well.

Also Note: JUnit @Rule for exception testing was deprecated in v 4.13

https://github.com/junit-team/junit4/wiki/Exception-testing#expectedexception-rule

      @Rule
      public ExpectedException expected = 
                       ExpectedException.none();

      @Test
      public void failsWithException(){

          expected.expect(RuntimeException.class);
          expected.expectMessage("catch me");
          throw new RuntimeException("catch me");
      }

Supporting Source Code

You can find the supporting source code for this over at:

And specifically: