Java JUnit Tests
Add Maven dependencies for JUnit[edit]
....
<dependencies>
....
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.8.2</version>
<scope>test</scope>
</dependency>
....
</dependencies>
....
Package structure to create tests[edit]
The convention is tu follow the structure shown on the image.
Test example[edit]
package com.luv2code.junitdemo;
import org.junit.jupiter.api.Test;
// import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.DisplayNameGeneration;
import org.junit.jupiter.api.DisplayNameGenerator;
import static org.junit.jupiter.api.Assertions.*;
// https://leeturner.me/posts/building-a-camel-case-junit5-displaynamegenerator/
// @DisplayNameGeneration(DisplayNameGenerator.Simple.class)
// @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class)
@DisplayNameGeneration(DisplayNameGenerator.IndicativeSentences.class)
class DemoUtilsTest {
DemoUtils demoUtils;
@BeforeAll
static void setUpClass() {
System.out.println("Cleanup before all tests")
}
@BeforeEach
void setUp{
demoUtils = new DemoUtils();
int expected = 6;
}
@Test
// @DisplayName("Null and Not Null")
void testEqualsAndNotEquals() {
// Execute
int actual = demoUtils.add(2, 4);
// Assert
assertEquals(expected, actual, "2 + 4 must be 6");
}
@Test
void testNullAndNotNull(){
String str1 = null;
String str2 = "luv2code";
assertNull(demoUtils.checkNull(str1), "Object should be null");
assertNull(demoUtils.checkNull(str2), "Object should not be null");
}
@AfterEach
void tearDownAfterEach(){
System.out.println("Cleanup After each test");
}
@AfterAll
static void cleanUpClass(){
System.out.println("Cleanup After all tests");
}
}
Custom displayName generator for camelCase with numbers[edit]
static class ReplaceCamelCaseEmojis extends ReplaceCamelCase {
public ReplaceCamelCaseEmojis() {
}
public String generateDisplayNameForClass(Class<?> testClass) {
return this.replaceWithEmojis(super.generateDisplayNameForClass(testClass));
}
public String generateDisplayNameForNestedClass(Class<?> nestedClass) {
return this.replaceWithEmojis(super.generateDisplayNameForNestedClass(nestedClass));
}
public String generateDisplayNameForMethod(Class<?> testClass, Method testMethod) {
return this.replaceWithEmojis(super.generateDisplayNameForMethod(testClass, testMethod));
}
private String replaceWithEmojis(String name) {
name = name.replaceAll("Camel|camel", "\uD83D\uDC2B");
name = name.replaceAll("Case|case", "\uD83D\uDCBC");
name = name.replaceAll("Display|display", "\uD83D\uDCBB");
name = name.replaceAll("Divisible|divisible", "\u2797");
name = name.replaceAll("Year|year", "\uD83D\uDCC5");
name = name.replaceAll("100", "\uD83D\uDCAF");
return name;
}
}
Run unit test[edit]
All tests[edit]
mvn test
Single test[edit]
mvn -Dtest=TestMessageBuilder test
Single test method from one test class[edit]
mvn -Dtest=TestMessageBuilder#testHelloWorld test
JUnit Assertions[edit]
import static org.junit.jupiter.api.Assertions.*;
org.junit.jupiter.api.Assertions contains JUnit Assertions
assertEquals(expected, actual, optional_message)
assertNotEquals(unexpected, actual, optional_message)
assertNull()
assertNotNull()
assertSame(object1, object1, message)
assertNotSame(object1, object1, message)
assertTrue(boolvariable, message)
assertFalse(boolvariable, message)
assertArraysEqual(array1, array2, message)
assertIterableEquals(iterable1, iterable2 message)
assertLinesMatch??
assertThrows(Exception.class, ()-> {functionCallThatThrowsError(params);})
assertDoesNotThrows( ()-> {functionCallThatDoesNotThrowsError(params);})
assertTimeoutPreemptively(Duration.ofSeconds(3), () -> { demoUtils.checkTimeout(); }, "Method should execute in 3 seconds");
Run tests in order[edit]
By default the order of the tests is deterministic but not obious, you can force the order
// MethodOrderer.DisplayName, MethodOrderer..MethodName, MethodOrderer.Random, MethodOrderer.OrderAnnotation
@TestMethodOrder(MethodOrderer.DisplayName.class)
class DemoUtilsTest {
...
@DisplayName("Equals and not equals")
void testEqualsAndNotEquals()...
// ----------------------------------------------
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
class DemoUtilsTest {
...
@DisplayName("Equals and not equals")
@Order(1)
void testEqualsAndNotEquals()...
Configure maven to run tests[edit]
pom.xml
<dependency>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M5</version>
<scope>test</scope>
</dependency>
Code coverage[edit]
IntelliJ has built-in support for code coverage Maven can too, requires plugin like maven-surefire-report-plugin
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-report-plugin</artifactId>
<version>3.0.0-M5</version>
<executions>
<execution>
<phase>test</phase>
<goals>
<goal>report</goal>
<goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
mvn clean test
mvn site -DgenerateReports=false
// at the surefire plugin
....
<configuration>
<testFailureIgnore>true</testFailureIgnore>
<statelessTestsetReporter implementation="org.apache.maven.plugin.surefire.extensions.junit5.JUnit5Xml30StatelessReporter">
<usePhrasedTestCaseMethodName>true</usePhrasedTestCaseMethodname>
</statelessTestsetReporter>
</configuration>
</plugin>
.....
JaCoCo (Java Code Coverage)[edit]
...
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.7</version>
<executions>
<execution>
<id>jacoco-prepare</id>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>jacoco-report</id>
<phase>test</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
</executions>
</plugin>
....
Disable tests[edit]
class ConditionalTest {
@Test
@Disabled("Dont run this test until ticket @34 is solved")
void basicTest() {}
@Test
@EnabledOnOs(OS.WINDOWS, OS.MAC, OS.LINUX)
void testForAllSystems() {}
@Test
@EnabledOnJre(JRE.JAVA_17)
void testOnJavaVersion() {}
@Test
@EnabledOnJreRange(min=JRE.JAVA_13, max=JRE.JAVA_18) // If only min provided works until latest java
void testOnJavaVersionRange() {}
@Test
@EnabledIfSystemProperty(named="SOMEPROPERTYNAME", matches="SOMEVALUE")
void testOnJavaVersion() {}
@Test
@EnabledIfEnvironmentVariable(named="SOMEPROPERTYNAME", matches="SOMEVALUE")
void testOnJavaVersion() {}
}
Parameterized Tests[edit]
// @parameterizedTest
@parameterizedTest(name="value={0}, expected={1}")
/* @CsvSource({
"1,1",
"2,2",
"3,Fizz",
"4,4",
"5,Buzz"
})*/
@CsvFileSource(resources="/small-test-data.csv") // src/test/resources/small-test-data.csv
void testCsvData(int value, String expected){
assertEquals(expected, FizzBuzz.compute(value));
}