Java Unit Testing with JUnit Example
This is an article forJava Unit Testing with JUnit Example.
You can also check this tutorial in the following video:
1. Introduction
Java unit testing is a software testing where methods and classes are tested.JUnit is a unit testing framework for the Java programming language which provides a way to test the application as many as you want. Unit testing usually includes the following steps:
- define a test
- create an instance of the testing class
- prepare the test data
- execute a test
- verify the testing results
- report the testing results
JUnit supports step 1 via@Test annotation, step 4 via@RunWith annotation, and step 5 via assertion API. In this example, I will create a multi-module maven project to demonstrate how to utilize the JUnit framework to create a test class.
2. Technologies Used
The example code in this article was built and run using:
- Java 11
- Maven 3.3.9
- Eclipse Oxygen
- JUnit (4 and 5)
3. Maven Multi-Modules Project
JUnit 5 was released in 2017. It is not backwards compatible withJUnit 4 which released in 2006. In this step, I will demonstrate both JUnit 4 and JUnit 5 in a three-module Maven project:
common– includes a main class –SomeClass.JUnit4-demo– testsSomeClasswith JUnit 4.JUnit5-demo– testsSomeClasswith JUnit 5.
3.1 Parent POM
Parentpom.xml includes three modules and two common build plug-ins:
maven-compiler-plugin– defines the Java 11 for the compilermaven-surefire-plugin– defines the JUnit report plug-in
pom.xml
<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>jcg.zheng.demo</groupId><artifactId>junit-demo</artifactId><version>0.0.1-SNAPSHOT</version><packaging>pom</packaging><name>junit-demo</name><url>http://maven.apache.org</url><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><description>parent project for junit demo</description><modules><module>common</module><module>junit4-demo</module><module>junit5-demo</module></modules><build><plugins><plugin><artifactId>maven-compiler-plugin</artifactId><version>3.8.0</version><configuration><release>11</release></configuration></plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-surefire-plugin</artifactId><version>3.0.0-M3</version></plugin></plugins></build></project>
Execute mvn clean install command and capture the output here:
[INFO] Reactor Summary for junit-demo 0.0.1-SNAPSHOT:[INFO][INFO] junit-demo ......................................... SUCCESS [ 2.287 s][INFO] comon .............................................. SUCCESS [ 10.295 s][INFO] junit4-demo ........................................ SUCCESS [ 6.631 s][INFO] junit5-demo ........................................ SUCCESS [ 6.191 s][INFO] ------------------------------------------------------------------------[INFO] BUILD SUCCESS[INFO] ------------------------------------------------------------------------[INFO] Total time: 26.052 s[INFO] Finished at: 2020-03-30T20:46:54-05:00[INFO] ------------------------------------------------------------------------
4. Common Module
In this step, I will create a common module which contains a main class. The main class will be tested at both JUnit 4 and JUnit 5 at its respective module.
4.1 POM
Thecommon module’spom.xml is defined as the following:
pom.xml
<?xml version="1.0"?><projectxsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><modelVersion>4.0.0</modelVersion><parent><groupId>jcg.zheng.demo</groupId><artifactId>junit-demo</artifactId><version>0.0.1-SNAPSHOT</version></parent><artifactId>common</artifactId><name>comon</name><url>http://maven.apache.org</url></project>
4.2 SomeClass
In this step, I will createSomeClass which has the following methods:
doubleANumber– return an integer number by multiplying two.returnABoolean– return abooleanvalue based on the input string value.voidFoo– does not return anything and throws an exception when receiving a bad argument.
SomeClass.java
package jcg.zheng.demo;public class SomeClass { public int doubleANumber(int num) {return num * 2;}public boolean returnABoolean(String inputData) {if ("Save".equalsIgnoreCase(inputData)) {return true;} else {return false;}}public void voidFoo(String inputData) {if ("Ok".equalsIgnoreCase(inputData)) {System.out.println("doing something.");;} else {throw new IllegalArgumentException("Bad argument:" + inputData);}}}5. JUnit 4 Module
JUnit 4 was first released in 2006. It only has one jar and requires JDK 5 or higher version.
5.1 POM
TheJUnit4-demo module’spom.xml and depends on JUnit 4 and thecommon module.
In this step, I will create a JUnit 4 test class to testSomeClass.
pom.xml
<?xml version="1.0"?><projectxsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><modelVersion>4.0.0</modelVersion><parent><groupId>jcg.zheng.demo</groupId><artifactId>junit-demo</artifactId><version>0.0.1-SNAPSHOT</version></parent><artifactId>junit4-demo</artifactId><name>junit4-demo</name><url>http://maven.apache.org</url><properties><junit.version>4.12</junit.version></properties><dependencies><dependency><groupId>jcg.zheng.demo</groupId><artifactId>common</artifactId><version>0.0.1-SNAPSHOT</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>${junit.version}</version><scope>test</scope></dependency></dependencies></project>5.2 SomeClassTest
In this step, I will create aSomeClassTest class in JUnit 4.
- Define a test with
@org.junit.Test - Print out a test name with a
@org.junit.Ruleon aorg.junit.rules.TestNameclass - Setup the test before each tests with
@org.junit.Before - Ignore a test with
@org.junit.Ignore - Set a test with a timeout limitation
- Set a test with an expected exception
- Verify the testing result with the expected value with a static class
org.junit.Assert
SomeClassTest.java
package jcg.zheng.demo.junit4;import static org.junit.Assert.assertEquals;import static org.junit.Assert.assertFalse;import static org.junit.Assert.assertTrue;import static org.junit.Assert.fail;import org.junit.Before;import org.junit.Ignore;import org.junit.Rule;import org.junit.Test;import org.junit.rules.TestName;import jcg.zheng.demo.SomeClass;public class SomeClassTest {private SomeClass classUnderTest = new SomeClass();@Rulepublic TestName testName = new TestName();@Beforepublic void setup() {classUnderTest = new SomeClass();System.out.println("Start " + testName.getMethodName());}@Testpublic void test_doubleANumber() {assertEquals(6, classUnderTest.doubleANumber(3));}@Ignorepublic void test_not_executed() {fail("It should not executed");}@Testpublic void test_returnBooleanFoo_false() {boolean shouldReturnFalse = classUnderTest.returnABoolean("NA");assertFalse(shouldReturnFalse);}@Testpublic void test_returnBooleanFoo_true() {boolean shouldReturnTrue = classUnderTest.returnABoolean("Save");assertTrue(shouldReturnTrue);}@Testpublic void test_voidFoo() throws IllegalAccessException {try {classUnderTest.voidFoo("OK");} catch (Exception e) {fail("Should not throw exception");}}@Test(expected = IllegalArgumentException.class)public void test_voidFoo_exception() throws IllegalAccessException {classUnderTest.voidFoo("NA");}@Test(timeout = 1)public void test_timeout() {classUnderTest.doubleANumber(9999);}}- Line 20, 26 – the
TestNameinstance marked by@Rulecan access the test name. - Line 23 – the method marked with
@Beforewill be invoked before executing each test. - Line 29 –
@Testmarks a method as a test. It will be executed by the JUnit default runner. - Line 34 – JUnit runner will ignore test tests which marks with
@Ignore. - Line 31, 42, 48 – invokes
assertFalse,assertTrue,assertEqualsto verify the test results to the expected value. - Line 60 – catch the expected exception.
- Line 65 – set up the timeout limit.
Output
[INFO] -------------------------------------------------------[INFO] T E S T S[INFO] -------------------------------------------------------[INFO] Running jcg.zheng.demo.junit4.SomeClassTestStart test_voidFoodoing something.Start test_returnBooleanFoo_falseStart test_voidFoo_exceptionStart test_doubleANumberStart test_timeoutStart test_returnBooleanFoo_true[INFO] Tests run: 6, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.214 s - in jcg.zheng.demo.junit4.SomeClassTest[INFO][INFO] Results:[INFO][INFO] Tests run: 6, Failures: 0, Errors: 0, Skipped: 0
6. JUnit 5 Module
JUnit 5 was first released in 2017. It requires JDK 8 or higher. It includes a collection of three sub-projects: JUnit Jupiter, JUnit Platform, and JUnit Vintage.
6.1 POM
TheJUnit5-demo module’spom.xml depends on JUnit 5 and common modules. Please note that it includes two of JUnit 5 modules:junit-jupiter-engineandjunit-jupiter-api.
In this step, I will create a JUnit 5 test class to testSomeClass.
pom.xml
<?xml version="1.0"?><projectxsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><modelVersion>4.0.0</modelVersion><parent><groupId>jcg.zheng.demo</groupId><artifactId>junit-demo</artifactId><version>0.0.1-SNAPSHOT</version></parent><artifactId>junit5-demo</artifactId><name>junit5-demo</name><url>http://maven.apache.org</url><properties><junit-jupiter.version>5.5.2</junit-jupiter.version></properties><dependencies><dependency><groupId>jcg.zheng.demo</groupId><artifactId>common</artifactId><version>0.0.1-SNAPSHOT</version></dependency> <dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter-engine</artifactId><version>${junit-jupiter.version}</version><scope>test</scope></dependency><dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter-api</artifactId><version>${junit-jupiter.version}</version><scope>test</scope></dependency></dependencies></project>6.2 SomeClassTest
In this step, I will create aSomeClassTest class in JUnit 5.
- Define a test with
@org.junit.jupiter.api.Test - Define a display name with
@org.junit.jupiter.api.DisplayName - Print out a test name from
@org.junit.jupiter.api.TestInfo - Setup the test before each tests with
@org.junit.jupiter.api.BeforeEach - Ignore a test with
@org.junit.jupiter.api.Disabled - Set a test with the
org.junit.jupiter.api.assertTimeoutmethod - Catch an exception with the
org.junit.jupiter.api.assertThrowmethod - Verify the testing result with the expected value with a
staticclass:org.junit.jupiter.api.Assertions
SomeClassTest.java
package jcg.zheng.demo.junit5;import static org.junit.jupiter.api.Assertions.assertEquals;import static org.junit.jupiter.api.Assertions.assertFalse;import static org.junit.jupiter.api.Assertions.assertThrows;import static org.junit.jupiter.api.Assertions.assertTimeout;import static org.junit.jupiter.api.Assertions.assertTrue;import static org.junit.jupiter.api.Assertions.fail;import java.time.Duration;import org.junit.jupiter.api.BeforeEach;import org.junit.jupiter.api.Disabled;import org.junit.jupiter.api.DisplayName;import org.junit.jupiter.api.RepeatedTest;import org.junit.jupiter.api.Test;import org.junit.jupiter.api.TestInfo;import org.junit.jupiter.api.TestReporter;import jcg.zheng.demo.SomeClass;public class SomeClassTest {private SomeClass classUnderTest;private TestInfo testInfo;private TestReporter testReporter;@BeforeEachpublic void setup(TestInfo testInfo, TestReporter terstReporter ) {this.testInfo = testInfo;this.testReporter = terstReporter;classUnderTest = new SomeClass();}@RepeatedTest(5)public void test_doubleANumber() {assertEquals(6, classUnderTest.doubleANumber(3), "it should return 6");}@Disabledpublic void test_not_executed() {fail("It should not executed");}@Test@DisplayName("It should return false when input data isn't Save")public void test_returnBooleanFoo_false() {boolean shouldReturnFalse = classUnderTest.returnABoolean("NA");assertFalse(shouldReturnFalse);}@Test@DisplayName("It should return true when input data is Save")public void test_returnBooleanFoo_true() {boolean shouldReturnTrue = classUnderTest.returnABoolean("Save");assertTrue(shouldReturnTrue);testReporter.publishEntry(testInfo.getDisplayName());}@Testpublic void test_voidFoo() throws IllegalAccessException { try {classUnderTest.voidFoo("OK");} catch (Exception e) {fail("Should not throw exception");}}@Testpublic void test_voidFoo_exception() throws IllegalAccessException {assertThrows(IllegalArgumentException.class, () -> {classUnderTest.voidFoo("NA");});}@Testpublic void test_timeout() {assertTimeout(Duration.ofMillis(1), ()-> classUnderTest.doubleANumber(1000));}}- Line 28 –
@BeforeEachmarks the method to be executed for each test. - Line 29 – can inject
TestInfoandTestReporterfrom Junit framework. - Line 35 –
@RepeatedTestannotation is a new annotation in Junit 5 which executes the test repeatedly. - Line 40 –
@Disabledannotation replaces the@Ignoreannotation in Junit 4. - Line 45 –
@Testinorg.junit.jupiter.apipackage marks a test. - Line 46 –
@DisplayNameis a new annotation which names the test with a more meaningful name. - Line 72 –
assertThrowsin JUnit 5 replaces the@Test‘sexpectedattribute in Junit 4 . - Line 80 –
assertTimeoutin JUnit 5 replaces the@Test‘stimeoutattribute in Junit 4 .
Output
[INFO] -------------------------------------------------------[INFO] T E S T S[INFO] -------------------------------------------------------[INFO] Running jcg.zheng.demo.junit5.SomeClassTestdoing something.[INFO] Tests run: 10, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.254 s - in jcg.zheng.demo.junit5.SomeClassTest[INFO][INFO] Results:[INFO][INFO] Tests run: 10, Failures: 0, Errors: 0, Skipped: 0
In Eclipse IDE, you can see the test with the display name.

7. Summary
In this example, I demonstrated how to write a unit test in JUnit. Here are the major differences between JUnit 4 and JUnit 5:
| JUnit 4 | JUnit 5 | |
| Required JDK | 5 (+) | 8 (+) |
| Package | org.junit | org.junit.jupiter |
| Annotation | @Before | @BeforeEach |
@After | @AfterEach | |
@BeforeClass | @BeforeAll | |
@AfterClass | @AfterAll | |
@Ignore | @Disabled | |
| – | @DisplayName | |
| – | @RepeatedTest | |
| @Category | @Tag | |
| @RunWith | @ExtendWith |
8. Download the Source Code
You can download the full source code of this example here:Java Unit Testing with JUnit Example

Thank you!
We will contact you soon.




