junit

Java Unit Testing with JUnit Example

Photo of Mary ZhengMary ZhengApril 3rd, 2020Last Updated: July 7th, 2022
1 536 6 minutes read

This is an article forJava Unit Testing with JUnit Example.

You can also check this tutorial in the following video:

JUnit Testing in Java – 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:

  1. define a test
  2. create an instance of the testing class
  3. prepare the test data
  4. execute a test
  5. verify the testing results
  6. 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 – testsSomeClass with JUnit 4.
  • JUnit5-demo – testsSomeClass with 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 compiler
  • maven-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 aboolean value 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.Rule on aorg.junit.rules.TestName class
  • 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 classorg.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 – theTestName instance marked by@Rule can access the test name.
  • Line 23 – the method marked with@Before will be invoked before executing each test.
  • Line 29 –@Test marks 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 – invokesassertFalse,assertTrue,assertEquals to 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 theorg.junit.jupiter.api.assertTimeout method
  • Catch an exception with theorg.junit.jupiter.api.assertThrow method
  • Verify the testing result with the expected value with astatic class: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 –@BeforeEach marks the method to be executed for each test.
  • Line 29 – can injectTestInfo andTestReporter from Junit framework.
  • Line 35 –@RepeatedTest annotation is a new annotation in Junit 5 which executes the test repeatedly.
  • Line 40 –@Disabled annotation replaces the@Ignore annotation in Junit 4.
  • Line 45 –@Test inorg.junit.jupiter.api package marks a test.
  • Line 46 –@DisplayName is a new annotation which names the test with a more meaningful name.
  • Line 72 –assertThrows in JUnit 5 replaces the@Test‘sexpected attribute in Junit 4 .
  • Line 80 –assertTimeout in JUnit 5 replaces the@Test‘stimeout attribute 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.

JUnit Example - JUnit 5 Result
Figure 1 JUnit 5 Result

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 4JUnit 5
Required JDK5 (+)8 (+)
Packageorg.junitorg.junit.jupiter
Annotation@Before@BeforeEach
@After@AfterEach
@BeforeClass@BeforeAll
@AfterClass@AfterAll
@Ignore@Disabled
@DisplayName
@RepeatedTest
@Category@Tag
@RunWith@ExtendWith

8. Download the Source Code

Download
You can download the full source code of this example here:Java Unit Testing with JUnit Example
Do you want to know how to develop your skillset to become aJava Rockstar?
Subscribe to our newsletter to start Rockingright now!
To get you started we give you our best selling eBooks forFREE!
1. JPA Mini Book
2. JVM Troubleshooting Guide
3. JUnit Tutorial for Unit Testing
4. Java Annotations Tutorial
5. Java Interview Questions
6. Spring Interview Questions
7. Android UI Design
and many more ....
I agree to theTerms andPrivacy Policy

Thank you!

We will contact you soon.

Photo of Mary ZhengMary ZhengApril 3rd, 2020Last Updated: July 7th, 2022
1 536 6 minutes read
Photo of Mary Zheng

Mary Zheng

Mary has graduated from Mechanical Engineering department at ShangHai JiaoTong University. She also holds a Master degree in Computer Science from Webster University. During her studies she has been involved with a large number of projects ranging from programming and software engineering. She works as a senior Software Engineer in the telecommunications sector where she acts as a leader and works with others to design, implement, and monitor the software solution.
    Subscribe
    Notify of
    guest
    I agree to theTerms andPrivacy Policy
    The comment form collects your name, email and content to allow us keep track of the comments placed on the website. Please read and accept our website Terms and Privacy Policy to post a comment.

    I agree to theTerms andPrivacy Policy
    The comment form collects your name, email and content to allow us keep track of the comments placed on the website. Please read and accept our website Terms and Privacy Policy to post a comment.