Unit Testing with JUnit 4 (2025)

3.1. Defining test methods

JUnit uses annotations to mark methods as test methods and to configure them.The following table gives an overview of the most important annotations in JUnit for the 4.x and 5.x versions.All these annotations can be used on methods.

Table 1. Annotations
JUnit 4Description

import org.junit.*

Import statement for using the following annotations.

@Test

Identifies a method as a test method.

@Before

Executed before each test. It is used toprepare the test environment (e.g., read inputdata, initialize the class).

@After

Executed after each test. It is used to cleanup the test environment (e.g., delete temporary data, restore defaults). It can also save memory by cleaning up expensive memory structures.

@BeforeClass

Executed once, before the start of all tests.It is used to perform time intensive activities, for example, to connect to a database. Methods marked with this annotation need to be defined as static to work with JUnit.

@AfterClass

Executed once, after all tests have been finished.It is used to perform clean-up activities, for example, to disconnect from a database. Methods annotated with this annotation need to be defined as static to work with JUnit.

@Ignore or @Ignore("Why disabled")

Marks that the test should be disabled. This is useful when theunderlying code has been changed and the test case has notyetbeenadapted. Or if the execution time of this test is too longto beincluded. It is best practice to providethe optionaldescription, why the test is disabled.

@Test (expected = Exception.class)

Fails if the method does not throw the named exception.

@Test(timeout=100)

Fails if the method takes longer than 100 milliseconds.

3.2. Assert statements

JUnit provides static methods to test for certain conditions via the Assert class.These assert statements typically start with assert.They allow you to specify the error message, the expected and the actual result.An assertion method compares the actual value returned by a test to the expected value.It throws an AssertionException if the comparison fails.

The following table gives an overview of these methods.Parameters in [] brackets are optional and of type String.

Table 2. Methods to assert test results
StatementDescription

fail([message])

Let the method fail. Might be used to check that a certain part of the code is not reached or to have a failing test before the test code is implemented.The message parameter is optional.

assertTrue([message,] boolean condition)

Checks that the boolean condition is true.

assertFalse([message,] boolean condition)

Checks that the boolean condition is false.

assertEquals([message,] expected, actual)

Tests that two values are the same. Note: for arrays the reference is checked not the content of the arrays.

assertEquals([message,] expected, actual, tolerance)

Test that float or double values match. The tolerance is the number of decimals which must be the same.

assertNull([message,] object)

Checks that the object is null.

assertNotNull([message,] object)

Checks that the object is not null.

assertSame([message,] expected, actual)

Checks that both variables refer to the same object.

assertNotSame([message,] expected, actual)

Checks that both variables refer to different objects.

3.3. JUnit test suites

If you have several test classes, you can combine them into a test suite.Running a test suite executes all test classes in that suite in the specified order.A test suite can also contain other test suites.

The following example code demonstrates the usage of a test suite.It contains two test classes (MyClassTest and MySecondClassTest).If you want to add another test class, you can add it to the @Suite.SuiteClasses statement.

package com.vogella.junit.first;import org.junit.runner.RunWith;import org.junit.runners.Suite;import org.junit.runners.Suite.SuiteClasses;@RunWith(Suite.class)@SuiteClasses({ MyClassTest.class, MySecondClassTest.class })public class AllTests {}

3.4. Disabling tests

The @Ignore annotation allow to statically ignore a test.Alternatively you can use Assume.assumeFalse or Assume.assumeTrue to define a condition for the test.Assume.assumeFalse marks the test as invalid, if its condition evaluates to true.Assume.assumeTrue evaluates the test as invalid if its condition evaluates to false.For example, the following disables a test on Linux:

Assume.assumeFalse(System.getProperty("os.name").contains("Linux"));

3.5. Parameterized test

JUnit allows you to use parameters in a tests class.This class can contain one test method and this method is executed with the different parameters provided.

You mark a test class as a parameterized test with the @RunWith(Parameterized.class) annotation.

Such a test class must contain a static method annotated with the @Parameters annotation.That method generates and returns a collection of arrays.Each item in this collection is used as parameter for the test method.

You can use the @Parameter annotation on public fields to get the test values injected in the test.

The following code shows an example for a parameterized test.It tests the multiply() method of the MyClass class which is included as inner class for the purpose of this example.

package testing;import org.junit.Test;import org.junit.runner.RunWith;import org.junit.runners.Parameterized;import org.junit.runners.Parameterized.Parameters;import java.util.Arrays;import java.util.Collection;import static org.junit.Assert.assertEquals;import static org.junit.runners.Parameterized.*;@RunWith(Parameterized.class)public class ParameterizedTestFields { // fields used together with @Parameter must be public @Parameter(0) public int m1; @Parameter(1) public int m2; @Parameter(2) public int result; // creates the test data @Parameters public static Collection<Object[]> data() { Object[][] data = new Object[][] { { 1 , 2, 2 }, { 5, 3, 15 }, { 121, 4, 484 } }; return Arrays.asList(data); } @Test public void testMultiplyException() { MyClass tester = new MyClass(); assertEquals("Result", result, tester.multiply(m1, m2)); } // class to be tested class MyClass { public int multiply(int i, int j) { return i *j; } }}

Alternatively to using the @Parameter annotation you can use a constructor in which you store the values for each test.The number of elements in each arrayprovided bythemethod annotated with@Parametersmustcorrespond to the number of parameters in theconstructor of theclass.The class is created for each parameter andthe testvalues arepassedvia the constructor to the class.

package de.vogella.junit.first;import static org.junit.Assert.assertEquals;import java.util.Arrays;import java.util.Collection;import org.junit.Test;import org.junit.runner.RunWith;import org.junit.runners.Parameterized;import org.junit.runners.Parameterized.Parameters;@RunWith(Parameterized.class)public class ParameterizedTestUsingConstructor { private int m1; private int m2; public ParameterizedTestUsingConstructor(int p1, int p2) { m1 = p1; m2 = p2; } // creates the test data @Parameters public static Collection<Object[]> data() { Object[][] data = new Object[][] { { 1 , 2 }, { 5, 3 }, { 121, 4 } }; return Arrays.asList(data); } @Test public void testMultiplyException() { MyClass tester = new MyClass(); assertEquals("Result", m1 * m2, tester.multiply(m1, m2)); } // class to be tested class MyClass { public int multiply(int i, int j) { return i *j; } }}

If you run this test class, the test method is executed with each defined parameter.In the above example the test method is executed three times.

A more flexible and easier to write approach is provided by the JUnitParams from https://github.com/Pragmatists/JUnitParams.

3.6. JUnit Rules

Via JUnit rules you can add behavior to each tests in a test class.You can annotate fields of type TestRule with the @Rule annotation.You can create objects which can be used and configured in your test methods.This adds more flexibility to your tests.You could, for example, specify which exception message you expect during the execution of your test code.

package de.vogella.junit.first;import org.junit.Rule;import org.junit.Test;import org.junit.rules.ExpectedException;public class RuleExceptionTesterExample { @Rule public ExpectedException exception = ExpectedException.none(); @Test public void throwsIllegalArgumentExceptionIfIconIsNull() { exception.expect(IllegalArgumentException.class); exception.expectMessage("Negative value not allowed"); ClassToBeTested t = new ClassToBeTested(); t.methodToBeTest(-1); }}

JUnit already provides several useful rule implementations.For example, the TemporaryFolder class allows to setup files and folders which are automatically removed after each test run.

The following code shows an example for the usage of the TemporaryFolder implementation.

package de.vogella.junit.first;import static org.junit.Assert.assertTrue;import java.io.File;import java.io.IOException;import org.junit.Rule;import org.junit.Test;import org.junit.rules.TemporaryFolder;public class RuleTester { @Rule public TemporaryFolder folder = new TemporaryFolder(); @Test public void testUsingTempFolder() throws IOException { File createdFolder = folder.newFolder("newfolder"); File createdFile = folder.newFile("myfilefile.txt"); assertTrue(createdFile.exists()); }}

For more examples of existing rules see https://github.com/junit-team/junit4/wiki/Rules.

3.7. Writing custom JUnit rules

To write your custom rule, you need to implement the TestRule interface.This interface defines the apply(Statement, Description) method which must return an instance of Statement.Statement represent the tests within the JUnit runtime and Statement#evaluate() run these.Description describes the individual test.It allows to read information about the test via reflection.

The following is a simple example for adding a log statement to an Android application before and after test execution.

package testing.android.vogella.com.asynctask;import android.util.Log;import org.junit.rules.TestRule;import org.junit.runner.Description;import org.junit.runners.model.Statement;public class MyCustomRule implements TestRule { private Statement base; private Description description; @Override public Statement apply(Statement base, Description description) { this.base = base; this.description = description; return new MyStatement(base); } public class MyStatement extends Statement { private final Statement base; public MyStatement(Statement base) { this.base = base; } @Override public void evaluate() throws Throwable { System. Log.w("MyCustomRule",description.getMethodName() + "Started" ); try { base.evaluate(); } finally { Log.w("MyCustomRule",description.getMethodName() + "Finished"); } } }}

To use this rule, simple add a field annotated with @Rule to your test class.

@Rulepublic MyCustomRule myRule = new MyCustomRule();

3.8. Categories

It is possible to define categories of tests and include or exclude them based on annotations.The following example is based on the JUnit 4.8 release notes.

public interface FastTests { /* category marker */}public interface SlowTests { /* category marker */}public class A { @Test public void a() { fail(); } @Category(SlowTests.class) @Test public void b() { }}@Category({ SlowTests.class, FastTests.class })public class B { @Test public void c() { }}@RunWith(Categories.class)@IncludeCategory(SlowTests.class)@SuiteClasses({ A.class, B.class })// Note that Categories is a kind of Suitepublic class SlowTestSuite { // Will run A.b and B.c, but not A.a}@RunWith(Categories.class)@IncludeCategory(SlowTests.class)@ExcludeCategory(FastTests.class)@SuiteClasses({ A.class, B.class })// Note that Categories is a kind of Suitepublic class SlowTestSuite { // Will run A.b, but not A.a or B.c}

3.9. JUnit static imports

Static import is a feature that allows fields and methods defined in a class as public static to be used without specifying the class in which the field is defined.

JUnit assert statements are typically defined as public static to allow the developer to write short test statements.The following snippet demonstrates an assert statement with and without static imports.

// without static imports you have to write the following statementAssert.assertEquals("10 x 5 must be 50", 50, tester.multiply(10, 5));// alternatively define assertEquals as static importimport static org.junit.Assert.assertEquals;// more code// use assertEquals directly because of the static importassertEquals("10 x 5 must be 50", 50, tester.multiply(10, 5));
Unit Testing with JUnit 4 (2025)

FAQs

How to ignore test in JUnit 4? ›

How to ignore test cases in JUnit 4: @Ignore. JUnit 4 offers the @Ignore annotation that you can use to tag the test cases you want to skip. You'll use this annotation like any other annotation: import package org.

How much unit testing is enough? ›

While there is no standard for unit testing, one number often cited in the testing world is 80%. "Eighty percent is what I usually see as the gating standard for code coverage in corporate shops," said Tim Ottinger, a senior consultant at Industrial Logic. "Any higher or lower than that is unusual."

Why use JUnit 5 over 4? ›

In contrast, JUnit 5 offers more granularity that makes it easier to work with especially when using the Maven and Gradle build systems. JUnit 4 only allows you to execute tests with one test runner at a time, while JUnit 5 allows more extensions at a time which lets you run multiple parallel tests.

Why unit testing is not enough? ›

Here's an example:

You mock a database dependency in your unit test for a service that writes data. The mock might return predictable results, but it can't simulate potential database errors or network issues. These real-world scenarios could cause integration issues that wouldn't be surfaced by unit tests alone.

What is JUnit 4 fail method? ›

Junit fail assertion method fails the test by throwing an assertion error, the fail method is used in junit version 4 and it will use the org. junit. Assert class. The junit fail method is used to verify that the actual exception will throw an error or the test is failing at the time of development.

How do you handle exceptions in JUnit 4? ›

When using JUnit 4, we can simply use the expected attribute of the @Test annotation to declare that we expect an exception to be thrown anywhere in the annotated test method. In this example, we've declared that we're expecting our test code to result in a NullPointerException.

How hard is unit testing? ›

Unit testing itself is rather easy once you understand how to do it. Even test driven or behavior driven development is easy one mastered… at least for the ideal scenario. What is the ideal scenario then? It is a unit test where the class under test has no external dependencies.

Should unit tests always pass? ›

A deterministic test always passes (if there are no issues) or always fails (when issues exist) on the same piece of code. The result of the test should not change as long as you don't change your code. By contrast, an unstable test is one that may pass or fail due to various conditions even if the code stays the same.

What is a good unit test first? ›

To write good unit tests apply the “FIRST-U” rules: Fast, Isolated/Independent, Repeatable, Self-validating, Timely and Understandable. Unit tests should be fast otherwise they will slow down your development/deployment time and will take longer time to pass or fail.

What is the test rule in JUnit 4? ›

A JUnit 4 rule is a component that intercepts test method calls and allows us to do something before a test method is run and after a test method has been run. All JUnit 4 rule classes must implement the org. junit.

How to tell if JUnit 4 or 5? ›

JUnit 4 follows the monolithic architecture and limited support for lambda expression. The JUnit 5 introduces new annotations like @Test, @BeforeEach, @AfterEach, @BeforeAll, and @AfterAll. And it supports additional annotations also for controlling the life cycle of the test cycle.

Can JUnit 4 and 5 be used together? ›

Junit 4 vs 5 - using both in same project

I prefer to use either JUnit 4 or JUnit 5, but there may be moments when we want to use both. We can do that with JUnit 5 dependencies. Rather than mixing the JUnit 4 and JUnit 5 dependencies, we might be able to get away with the JUnit 5 dependencies alone.

How can I improve my unit test? ›

Unit Testing Best Practices
  1. Arrange, Act, Assert. ...
  2. Use Relevant and High-Quality Test Data. ...
  3. One Assert Per Test Method. ...
  4. Avoid Test Interdependence. ...
  5. Write Tests before Code. ...
  6. Keep It Short, Sweet, and Visible. ...
  7. Use Headless Testing when Appropriate. ...
  8. Test Positive and Negative Scenarios.

What makes a bad unit test? ›

1 Test too much or too little

A good rule of thumb is to test only the public interface and behavior of your unit, and not the internal implementation details. You should also avoid testing trivial or obvious code, such as getters and setters, unless they have some logic or side effects.

What is a good unit test? ›

Unit tests should be able to run on every machine. Your team should be running them multiple times a day. They would run both during local builds and in your CI. You want them to run fast. Be sure to mock all external dependencies that might slow it down, like API calls, databases, or file system access.

How do I exclude a JUnit test? ›

The @Disabled annotation is used to exclude/skip execution of the tests from the test suite. A test method or class can be disabled using the @Disabled annotation. This annotation accepts one optional parameter where we can supply the reason for disabling the test.

How do you ignore a test method? ›

A test method annotated with @Ignore will not be executed. If a test class is annotated with @Ignore, then none of its test methods will be executed.

How do I stop a test execution in JUnit? ›

You can apply the @Disabled annotation to a class to disable all the tests in that class (suite).
  1. DisabledClassTest.java. @Disabled class DisabledClassTest { @Test void test() { fail("This test should not be executed"); } }
  2. DisabledMethodTest.java. ...
  3. DisabledClassTest.java.
Aug 25, 2023

How do I ignore one test in jest? ›

How to ignore test cases in jest? We can use test. skip, describe. skip functions to skip individual and blocks of tests in jest.

Top Articles
Latest Posts
Recommended Articles
Article information

Author: Jonah Leffler

Last Updated:

Views: 5275

Rating: 4.4 / 5 (65 voted)

Reviews: 88% of readers found this page helpful

Author information

Name: Jonah Leffler

Birthday: 1997-10-27

Address: 8987 Kieth Ports, Luettgenland, CT 54657-9808

Phone: +2611128251586

Job: Mining Supervisor

Hobby: Worldbuilding, Electronics, Amateur radio, Skiing, Cycling, Jogging, Taxidermy

Introduction: My name is Jonah Leffler, I am a determined, faithful, outstanding, inexpensive, cheerful, determined, smiling person who loves writing and wants to share my knowledge and understanding with you.