Skip to main content Skip to local navigation

jUnit 6: unit testing in Java

This past year has seen the release of an update to jUnit, arguably the most important testing framework in software engineering and computer science. Now in its sixth release, jUnit makes a significant jump to eliminating support in anything before Java 17. When I got started with Java in 2020 most of the teaching material that I encountered focused on Java 8. This meant that there was little mention of things like the Java Shell (jShell) that is so handy for people programming in Python or MATLAB because jShell was introduced in Java 9. There were improvements to String methods. Granted, there are some useful features after Java 17 (like guards on Switch and more consistency in Collections), but moving away from Java 8 with such an important tool as jUnit is an important signal.

jUnit options, including 4, 5 and 6 in IntelliJ.  Here, IntelliJ is asking whether jUnit6 should be added to the classpath.
jUnit options, including 4, 5 and 6 in IntelliJ. Here, IntelliJ is asking whether jUnit6 should be added to the classpath.

My EECS 1021 course material up until now has focused on jUnit 4 because it's an introductory class. That said, my colleagues have been using the improved jUnit 5 rather than 4. And the sixth release seems to be everything that's good about 5, but better and the latest release of IntelliJ, along with JDK 26, support it out of the box. One of the key features I want to use, and introduce my students to is the development of tests that are fed by a list of values in a CSV file -- and that's supported in Version 6. So I'm going to migrate from 4 to 6, skipping 5. On my blog pages I'll lay out some basic examples.

Key References for jUnit 6

jUnit 6 user guide: https://docs.junit.org/6.1.0/overview.html

The following examples were done with IntelliJ 2026, jUnit 6 and Oracle OpenJDK 27 (aarch64).

Basic Test: One plus one equals three?

Let's start with a really simple one: does 1+1 equal 3?

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

public class testFile {
    @Test
    public void test1(){
        assertEquals(3,(1+1),"test 1 failed.");
    }
}

What you should see in IntelliJ is something like this:

jUnit showing a failure.
jUnit showing a failure.

Tests 2 and 3: floating point values

What happens if you have some operation on floating point numbers and what to test the output? When looking for equality, you need to look for values within a particular range. Specifically, with jUnit, you're looking for a "delta" from the target value. Here's an example:

       @Test
    // Test 1.0001f + 1.0000f = 2.0001 (with really small delta)
    public void test2(){
        // The expected value is 2.0001.  However, it won't be due to how floating point values are made (like 2.0999212)
        // So, when adding two values together, a little error will be introduced.
        // I'll set my "delta" to something really small, naively assuming that equality should
        // hold (but it won't)
        assertEquals(2.0001f,(1.0001f + 1.0000f),0.0000001,"floats not equal.");
    }

The test will failure because we're looking for a "true" (or expected) value of 2.0001. However, the way floating point values work, only an approximation will be provided (2.000099897...). Adding 1.0001 and 1.0000 together won't yield 2.0001, either, again because one or both of those values will be a different approximation, adding up to 2.0001001358.... If my delta (error) value is set too low (like 0.0000001) the jUnit test will fail., as shown in the screenshot below:

jUnit test fail with a small delta
jUnit test fail with a small delta

But it will succeed for a different test setup:

    @Test
    // Test 1.0001f + 1.0000f = 2.0001 (with big delta)
    public void test3(){
        // The expected value is 2.0001.  However, it won't be due to how floating point values are made (like 2.0999212)
        // So, when adding two values together, a little error will be introduced.
        // I'll set my "delta" to something relatively big (0.001) to let it succeed.
        assertEquals(2.0001f,(1.0001f + 1.0000f),0.001,"floats not equal.");
    }

Which results in a pass:

jUnit test pass with large delta

Parameterized Tests

Doing one-off testing is fine. And you can string a number of these individual tests to explore a variety of inputs and outputs. However, there are better ways to organize batches of tests. jUnit5 introduced parameterized testing to jUnit. Here is a blog post from Mike my Bytes about parameterized tests in jUnit 5 and here is one at Ankarm.

Below, I've modified one of the Ankarm examples. I've set it up with four different tests and the middle two are wrong. (I've labelled them as "typo").

import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;

import static org.junit.jupiter.api.Assertions.assertEquals;
//  Source: https://ankurm.com/junit-6-parameterized-tests/


// Set up a new class to look at parameterized tests
public class testFile2Parameterized {

        // Source: https://ankurm.com/junit-6-parameterized-tests/

       // The following is a parameterized test.  Not an @Test.
        @ParameterizedTest(name = "{0} + {1} = {2}")        // Display the name while testing.
        @CsvSource({
                "-1,   2,   3",      // Test 1:  In_A, In_B, Out     ( 1 + 2 = 3 )
                "20,  20,  400",     // Test 2:  In_A, In_B, Out     (20 + 20 = 40 )  // Typo
                "10, 10, 5",      // Test 3:  In_A, In_B, Out      (-10 + 10 = 0 )      // Typo
                "20, -30, -10"      // Test 4:  In_A, In_B, Out     (20 - (-30) = -10)
        })
        // This is the test method.
        void testMethod1(int In_A, int In_B, int expectedSum) {
            Calculator calculator = new Calculator();
            assertEquals(expectedSum, calculator.add(In_A, In_B),
                    In_A + " + " + In_B + " should equal " + expectedSum);
        }
}

By taking advantage of the string in @ParameterizedTest label and the assertEquals method, jUnit will output important information for debugging, as you can see below.
Error messages from the jUnit6 class.
Error messages from the jUnit6 class for parameterized tests.

That's neat. Such a useful feature to be able to build large sets of sets. It appears that external CSV files can also be used... more on that later!

Conclusion

I'm pretty interested in the parameterized test feature that is available in jUnit 6. This will make it easier for my students to build large banks of tests. I don't recall having access to it in jUnit 4. Apparently, it uses the FastCSV library, which I think I may explore for inclusion in CSV activities in class.

That's it for now. I'll explore more jUnit 6 features later.


a pen

James Andrew Smith is a Professional Engineer and Associate Professor in the Electrical Engineering and Computer Science Department of York University’s Lassonde School, with degrees in Electrical and Mechanical Engineering from the University of Alberta and McGill University.  Previously a program director in biomedical engineering, his research background spans robotics, locomotion, human birth, music and engineering education. While on sabbatical in 2018-19 with his wife and kids he lived in Strasbourg, France and he taught at the INSA Strasbourg and Hochschule Karlsruhe and wrote about his personal and professional perspectives.  James is a proponent of using social media to advocate for justice, equity, diversity and inclusion as well as evidence-based applications of research in the public sphere. You can find him on Twitter.  You can find him on BlueSky. Originally from Québec City, he now lives in Toronto, Canada.