Skip to Content

JUnit: Automating Java Unit Tests

JUnit is an extremely popular tool that automates Java unit testing. It acts as the driver for testing Java classes, and although it this is mostly thought of as testing individual classes (unit testing), it can be used to drive tests for any level of integration testing below a complete system.

This page walks through a simple example of creating and executing simple JUnit tests. Note that we are using JUnit5 in this example.

Downloading JUnit

When you go to the JUnit home page, it redirects you to JUnit5. On the right hand side is a Latest Release box with links to the most recent versions. It says v1.10.0 as of this writing. This tutorial is using the Platform version of JUnit, but others use the Jupiter or Vintage versions that may integrate with other tools.

When you click on Platform, you are taken to another site that hosts the download files. Scroll down until you find “junit-platform-console-standalone”, and click on that. Then from the new page, select the Versions tab, then select Browse on the version at the top (1.10.0 for me). This takes you to a list of files available. There are too many choices! Javadoc, source, and other choices. You want the main jar file, in my case named junit-platform-console-standalone-1.10.0.jar ; you don’t need anything else for following this tutorial page. In my examples below I have 1.9.0 installed, but you can just change the name of the jarfile being referenced in the example commands.

Software Under Test (SUT)

For this example we use a simple Java class:

public class Bigger
{
    private int val;
    
    public Bigger(int v)
    {
        val = v;
    }

    // returns true if param is bigger than object value, false otherwise
    public boolean isBiggerThanMe(int otherVal)
    {
        if (otherVal >= val)
            return true;
        else
            return false;
    }
}

This code can be compiled using a simple

javac Bigger.java

Note that it does not have a main() method and so it is not a complete program and cannot be run by itself.

Creating a Single JUnit Test

JUnit tests are Java code! The great thing about JUnit is that your tests are Java code, and so writing tests is just writing code. JUnit provides you with helper library methods to make this easier, and provides the driver main() that actually finds and runs your tests.

Below is our initial JUnit code with just one test case:

import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.BeforeEach;

class BiggerTests {

Bigger big;

@BeforeEach
void BuildObject()
{
    big = new Bigger(12);
}

@Test
void EqClassNotBigger()
{
    boolean result;
    result = big.isBiggerThanMe(5);
    assertEquals(false,result);
}

} // end class

Junit5 uses Java Annotations in order to know how to use and run your tests. The @BeforeEach annotation tells JUnit to run this method before each test is run. In our example we are using it to create the object that will be used in the test. The @Test annotation is placed on each method that is an actual test case; JUnit will run these methods as individual tests.

A test should perform some code invocation(s) and then check the result(s). Each test method should encapsulate just one test case, though. JUnit has helper methods that are used to check the validity of the result; in this example we are using the assertEquals() helper to say that a passing result for this test is a boolean result of false.

JUnit test methods should have meaningful names! Don’t name your tests “test1” and so on, but name them something that tells you their purpose. And don’t be afraid to have long names, because you aren’t going to be calling them yourself. The test above is a test for a black-box equivalence class, in particular the equivalence class of values not bigger than the object value.

Compiling and Running the JUnit Test

Since JUnit tests are Java code, we have to compile them before running. The only thing needed to compile is to give the Java compiler a classpath so it can find the JUnit jarfile, something like this:

javac -cp /home/jcook/tools/junit/junit-platform-console-standalone-1.9.0.jar:. BiggerTests.java

Notice the “:.” on the end of the classpath, which includes the current directory in the classpath.

To run the JUnit tests, we run JUnit, not the class with our tests. But we have to give JUnit information to find and run our tests, like this:

java -jar /home/jcook/tools/junit/junit-platform-console-standalone-1.9.0.jar -cp . -c BiggerTests

This command tells Java to run the jarfile, and then with arguments we give the jarfile a classpath to find our code ("-cp ."), and then we tell it what class contains our tests ("-c BiggerTests"). When I run this, my output is:

Thanks for using JUnit! Support its development at https://junit.org/sponsoring

╷
├─ JUnit Jupiter ✔
│  └─ BiggerTests ✔
│     └─ EqClassNotBigger() ✔
├─ JUnit Vintage ✔
└─ JUnit Platform Suite ✔

Test run finished after 82 ms
[         4 containers found      ]
[         0 containers skipped    ]
[         4 containers started    ]
[         0 containers aborted    ]
[         4 containers successful ]
[         0 containers failed     ]
[         1 tests found           ]
[         0 tests skipped         ]
[         1 tests started         ]
[         0 tests aborted         ]
[         1 tests successful      ]
[         0 tests failed          ]

This shows me that JUnit found my one test case, EqClassNotBigger, and that my test case passed!

Adding More Tests

Now that this all works, adding more tests is a simple matter of adding more methods, all annotated with the @Test annotation. If we consider black box testing of our code, the Bigger.isBiggerThanMe() method has two equivalence classes, values smaller and values bigger, with the boundary at the value equal to the object value. Good black box testing tells us to have a general test for each equivalence class, and then to heavily test the boundaries. So we could add the following test methods to our BiggerTests class:

@Test
void EqClassBigger()
{
    boolean result;
    result = big.isBiggerThanMe(25);
    assertEquals(true,result);
}

@Test
void BoundaryOneLess()
{
    boolean result;
    result = big.isBiggerThanMe(11);
    assertEquals(false,result);
}

@Test
void BoundaryEqual()
{
    boolean result;
    result = big.isBiggerThanMe(12);
    assertEquals(false,result);
}

@Test
void BoundaryOneGreater()
{
    boolean result;
    result = big.isBiggerThanMe(13);
    assertEquals(true,result);
}

Now when we compile and run this whole set of tests, we get this output:

> javac -cp /home/jcook/tools/junit/junit-platform-console-standalone-1.9.0.jar:. BiggerTests.java 
> java -jar /home/jcook/tools/junit/junit-platform-console-standalone-1.9.0.jar -cp . -c BiggerTests

Thanks for using JUnit! Support its development at https://junit.org/sponsoring

╷
├─ JUnit Jupiter ✔
│  └─ BiggerTests ✔
│     ├─ EqClassBigger() ✔
│     ├─ BoundaryOneGreater() ✔
│     ├─ BoundaryOneLess() ✔
│     ├─ EqClassNotBigger() ✔
│     └─ BoundaryEqual() ✘ expected: <false> but was: <true>
├─ JUnit Vintage ✔
└─ JUnit Platform Suite ✔

Failures (1):
  JUnit Jupiter:BiggerTests:BoundaryEqual()
    MethodSource [className = 'BiggerTests', methodName = 'BoundaryEqual', methodParameterTypes = '']
    => org.opentest4j.AssertionFailedError: expected: <false> but was: <true>
    [...exception stack trace removed...]

Test run finished after 85 ms
[         4 containers found      ]
[         0 containers skipped    ]
[         4 containers started    ]
[         0 containers aborted    ]
[         4 containers successful ]
[         0 containers failed     ]
[         5 tests found           ]
[         0 tests skipped         ]
[         5 tests started         ]
[         0 tests aborted         ]
[         4 tests successful      ]
[         1 tests failed          ]

And in fact our code does have a bug at that point, so we found a bug!

More

Now that you have your tests automated in JUnit, you can run them as often as you want! Good regression testing needs this kind of test automation. Many companies re-run their test suites overnight, or even more often.

JUnit of course has other capabilities, and integrates with many other tools. You can learn all about that on your own!