Home

Publications

Projects

Teaching

Misc.

Test Runner

July 2, 2017

Test Runner

Build Status Coverage Status Maven Central

This project provides a framework to run JUnit tests in a new JVM. It allows to retrieve results using serialization / deserialization.

Supported Features:

/!\ WARNING the test runner is not able to run parametrized JUnit5 test methods.

API

The provided API is eu.stamp_project.testrunner.EntryPoint. This class provides several static methods to execute all the test methods of given test classes, specific test methods of a given test class, compute the code coverage with JaCoCo, etc.

Tests Execution

  1. Executing all the test methods of a test class.
// class TestResult explained below 
TestResult result = EntryPoint.runTests(String classpath, String fullQualifiedNameOfTestClass);

The classpath must contain all the dependencies required to execute the test. Elements must be separated by the system path separator. The fullQualifiedNameOfTestClass must be a correct full qualified name, e.g. my.package.TestClass. The folder that contains the compiled file of your project must be included in the classpath. The compiled (.class) of the test class to be executed must be included in the given classpath.

  1. Executing specific test methods of a given test class.
TestResult result = EntryPoint.runTests(String classpath, String fullQualifiedNameOfTestClass, String[] methodNames);

The two first parameters are the same above. The String array methodsNamescontains the name of test methods to be executed. Each of these test methods must be in the test class designated by the fullQualifiedNameOfTestClass.

Complete list:

// Execute all the test methods of a given test class
TestResult result = EntryPoint.runTests(String classpath, String fullQualifiedNameOfTestClass);

// Execute all the test methods of given test classes
TestResult result = EntryPoint.runTests(String classpath, String[] fullQualifiedNameOfTestClasses);

// Execute a specific test method of a given test class
TestResult result = EntryPoint.runTests(String classpath, String fullQualifiedNameOfTestClass, String methodName);

// Execute specific test methods of a given test class
TestResult result = EntryPoint.runTests(String classpath, String fullQualifiedNameOfTestClass, String[] methodNames);

// Execute specific test methods of given test classes
TestResult result = EntryPoint.runTests(String classpath, String[] fullQualifiedNameOfTestClasses, String[] methodNames); 
Output

The output of all runTests() API is a eu.stamp_project.testrunner.listener.TestResult.

This object provides all the information needed about the execution of test methods:

The method TestResult#aggregate(TestResult that) allows to aggregate the results. It returns a new TestResult that contains both test results, i.e. test result of the caller and the parameter. Example:

TestResult result1 = EntryPoint.runTests(classpath, eu.stamp_project.MyFirstTest);
TestResult result2 = EntryPoint.runTests(classpath, eu.stamp_project.MySecondTest);
TestResult allResult = result1.aggregate(result2); // contains both result1 and result2

Global Coverage with JaCoCo.

API to compute the coverage:

// Compute the instruction coverage of all the test methods of a given test class
Coverage coverage = EntryPoint.runCoverage(String classpath, String targetProjectClasses, String fullQualifiedNameOfTestClass);

// Compute the instruction coverage of all the test methods of given test classes
Coverage coverage = EntryPoint.runCoverage(String classpath, String targetProjectClasses, String[] fullQualifiedNameOfTestClasses);

// Compute the instruction coverage of a specific test method of a given test class
Coverage coverage = EntryPoint.runCoverage(String classpath, String targetProjectClasses, String fullQualifiedNameOfTestClass, String methodName);

// Compute the instruction coverage of specific test methods of a given test class
Coverage coverage = EntryPoint.runCoverage(String classpath, String targetProjectClasses, String fullQualifiedNameOfTestClass, String[] methodNames);

// Compute the instruction coverage of specific test methods of given test classes
Coverage coverage = EntryPoint.runCoverage(String classpath, String targetProjectClasses, String[] fullQualifiedNameOfTestClasses, String[] methodNames); 

String targetProjectClasses must contain both the absolute paths to the binaries of the program and of the binaries of the test suite. For a typical maven project, this is would be: <path_to_project>/target/classes:<path_to_project>/target/test-classes where <path_to_project> is the path to the project under test. Note that the separator, here : is used on Linux. You must use the system separator.

Output

The output of all runCoverage() API is a eu.stamp_project.testrunner.listener.Coverage.

The object provides the two following method:

Coverage per test methods

In the same way, you can have the coverage per test methods using runCoveragePerTestMethods() API of EntryPoint class.

Output

The output of all runCoveragePerTestMethods() API is a eu.stamp_project.testrunner.listener.CoveragePerTestMethod.

Covered results per test method

In the same way, you can have the covered results per test method using runCoveredTestResultPerTestMethods() API of EntryPoint class.

Online covered results per test method

In the same way, you can have the covered results per test method using runOnlineCoveredTestResultPerTestMethods() API of EntryPoint class.

Note that, in this case, all covered classes will be instrumented and recorded by default, or according to the jacoco parameters includes and excludes available through EntryPoint.jacocoAgentIncludes and EntryPoint.jacocoAgentExcludes respectively.

Output

The output of all runCoveredTestResultPerTestMethods() API is a eu.stamp_project.testrunner.listener.CoveredTestResultPerTestMethod.

WARNING: Detailed compressed coverage

Unlike other coverage transformers, which analyze the classes available under the source binary directories, this transformer analyzes all classes whose execution was recorded by jacoco, loading them from the system’s classloader.

Using this transformer outside the online mode provided through runOnlineCoveredTestResultPerTestMethods might result in classloading issues, as the executed classes may not be available or coherent between different classloaders.

Mutation Score

The test runner can now compute the mutation using PIT.

API:

List<? extends AbstractPitResult> EntryPoint.runPit(final String classpath, final String pathToRootProject, final String filterTargetClasses, final String targetTests)

classpath is the classpath of the application. It must contains all the dependencies, the source code and the test code. pathToRootProject is the path to the root folder of the project. filterTargetClasses is a regex that matches the application source code to be mutated. targetTests is a regex that matches test classes that will be executed to compute the mutation score.

Output

The output is a list of pit result. Pit results are encapsuled in two objects, depending on the output format used.

In any case, the pit result gives the following information:

Configuration

In EntryPoint class, you have access to several fields that allow to configure the execution:

Dependency:

You can add to your pom.xml:

<dependency>
    <groupId>eu.stamp-project</groupId>
    <artifactId>test-runner</artifactId>
    <version>2.0.8</version>
</dependency>

Development:

  1. clone:
git clone https://github.com/STAMP-project/testrunner.git
  1. build resources:
cd testrunner/src/test/resources/test-projects/
mvn install
  1. build testrunner:
cd ../../../..
mvn install

Please, open an issue if you have any question / suggestion. Pull request are welcome! 😃

Licence

TestRunner is published under LGPL-3.0 (see Licence.md for further details).

Funding

TestRunner is partially funded by research project STAMP (European Commission - H2020) STAMP - European Commission - H2020