Maven Tests
Maven Test
When you execute mvn test
it will compile and test the source code that's underneath the source code folder!
Maven Test allows integration with JUnit, TestNG, and POJO. We will go over JUnit because that's what we use most of the time.
JUnit
The popular testing framework for Java. Most of the test are written in JUnit 4 but the latest version is JUnit 5.
Writing them are still the same, however, integrating it with behavioral driven testing framework like Cucumber will be different I will go over the differences for using cucumber with JUnit 4 and JUnit 5 (Mainly in the annotation that is used to specify the glue and feature files)
When you write your unit tests using JUnit you want to structure your file directory like the following:
src
├── main
│ ├── java
│ │ └── test
│ │ └── App.java
│ └── resources
│ └── application.properties
└── test
├── java
│ └── test
│ └── AppTest.java
└── resources
└── test.json
Your main source code directory will contain two different directories.
- The
main
directory contain the Java source code for your application as well as any resources that your application uses - The
test
directory contain the Java source code used for testing. This is where you will be writing your unit test for your applications
When you run mvn test
it will compile the source code from the src
directory and execute the proper unit test using the JUnit framework.
Dependency needed for JUnit 5
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.9.1</version>
<scope>test</scope>
</dependency>
</dependencies>
Test Class
A test class is a class that will be used by Maven to carry out the testing.
A test class contains methods that will be tested by Maven. Maven use a pattern to check whether a class is a test class or name, the list of pattern used by Maven to determine if a class is a test class is of the following:
**/Test*.java
**/*Test.java
**/*Tests.java
**/*TestCase.java
Test Runner Class
This applies to JUnit 4 test. JUnit 5 has a new API and @RunWith is no longer needed.
A test runner in JUnit is just a simple class that implements the Describable
interface. The interface just have two abstract methods to implement:
public abstract class Runner implements Describable {
public abstract Description getDescription();
public abstract void run(RunNotifier notifier);
}
- getDescription: Is used to return a description containing the information about the test, this is used by different tools such as those from IDE
- run: This is used to actually run the test class or test suite
You can implement your own test runner to do custom logic for running tests, for example you can print out silly messages just before each test is run.
A simple test runner class implementation can be found below: All it does is before it runs the test class is it prints the message "MyRunner <TestClass>"
Eample Test Runner
//src/main/java/MinimalRunner
package com.codingninjas.testrunner;
import org.junit.runner.Description;
import org.junit.runner.Runner;
import org.junit.runner.notification.RunNotifier;
import org.junit.Test;
import java.lang.reflect.Method;
public class MinimalRunner extends Runner {
private Class testClass;
public MinimalRunner(Class testClass) {
super();
this.testClass = testClass;
}
//getDescription method inherited from Describable
@Override
public Description getDescription() {
return Description
.createTestDescription(testClass, "My runner description");
}
//our run implementation
@Override
public void run(RunNotifier notifier) {
System.out.println("running the tests from MyRunner: " + testClass);
try {
Object testObject = testClass.newInstance();
for (Method method : testClass.getMethods()) {
if (method.isAnnotationPresent(Test.class)) {
notifier.fireTestStarted(Description
.createTestDescription(testClass, method.getName()));
method.invoke(testObject);
notifier.fireTestFinished(Description
.createTestDescription(testClass, method.getName()));
}
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
To actually use this example Test Runner you would then just simply annotate your test class with @RunWith(MinimalRunner.class)
which will delegate the responsibility of running this particular test class to that custom test runner.
//src/test/java/CalculatorTest.java
package com.codingninjas.testrunner;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(MinimalRunner.class)
public class CalculatorTest {
Calculator calculator = new Calculator();
@Test
public void testAddition() {
System.out.println("in testAddition");
assertEquals("addition", 8, calculator.add(5, 3));
}
}
Note that this runner mechanism is no longer present in JUnit 5 and is replaced by Jupiter extension. https://stackoverflow.com/a/59360733/7238625
Default Test Runner class
For Junit 4 at least, if you don't specify a test runner, JUnit will default to the default BlockJUnit4ClassRunner
which as you know it will just simply executes the test class.