Skip to main content

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

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);
}
  1. getDescription: Is used to return a description containing the information about the test, this is used by different tools such as those from IDE
  2. 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.

Specify one test class to execute

If you only want to run one of the test class then you can run maven test with the following option

 mvn test -Dtest="TestFoo"

This will only execute the TestFoo class.

Specify one method to execute from a test class

If you only want to execute one of the test then you can run maven test with the following option

mvn test -Dtest="TestFoo#testFoo"

The left of # denotes the test class, and the right of # denotes the method that you want to execute.

Cucumber + JUnit 4