You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by ti...@apache.org on 2019/05/15 03:44:54 UTC

[maven-surefire] 02/04: repaired low jacoco coverage, powermock 2.0.2 @ java 1.7 and jacoco 0.8.4

This is an automated email from the ASF dual-hosted git repository.

tibordigana pushed a commit to branch 1546-1222
in repository https://gitbox.apache.org/repos/asf/maven-surefire.git

commit 9cb7751de2052eb8900ae3321edf7fd66d58d2f8
Author: tibordigana <ti...@apache.org>
AuthorDate: Mon Apr 29 21:31:53 2019 +0200

    repaired low jacoco coverage, powermock 2.0.2 @ java 1.7 and jacoco 0.8.4
---
 Jenkinsfile                                        |   3 -
 maven-failsafe-plugin/pom.xml                      |  30 ++++
 .../plugin/failsafe/IntegrationTestMojoTest.java   |   2 +-
 maven-surefire-common/pom.xml                      |  62 +++++++-
 .../AbstractSurefireMojoJava7PlusTest.java         |   2 +
 .../plugin/surefire/AbstractSurefireMojoTest.java  |  16 ++-
 .../maven/plugin/surefire/MojoMocklessTest.java    |  68 +++++++++
 .../maven/plugin/surefire/SurefireHelperTest.java  |  47 ++++++
 .../booterclient/DefaultForkConfigurationTest.java |   2 +
 .../JarManifestForkConfigurationTest.java          |   2 +
 .../plugin/surefire/report/TestSetStatsTest.java   |   2 +
 .../StatelessTestsetInfoReporterTest.java          |   2 +
 maven-surefire-plugin/pom.xml                      |  26 ++++
 .../maven/plugin/surefire/SurefirePluginTest.java  | 117 ++++++---------
 maven-surefire-report-plugin/pom.xml               |  27 ++++
 .../plugins/surefire/report/JUnit4SuiteTest.java   |  22 ++-
 pom.xml                                            | 160 ++++++++++-----------
 surefire-api/pom.xml                               |  24 ++++
 .../java/org/apache/maven/JUnit4SuiteTest.java     |   2 +
 .../maven/surefire/booter/CommandReaderTest.java   |   4 +-
 .../java/org/apache/maven/surefire/booter/Foo.java |   0
 .../surefire/booter/NewClassLoaderRunner.java      |   7 +-
 .../surefire/booter/SurefireReflectorTest.java     | 123 +++++++++++++++-
 surefire-booter/pom.xml                            |  36 +++--
 .../maven/surefire/booter/JUnit4SuiteTest.java     |  22 ++-
 .../surefire/booter/SurefireReflectorTest.java     | 154 --------------------
 .../maven/surefire/booter/SystemUtilsTest.java     |   5 +-
 surefire-extensions-api/pom.xml                    |  56 ++++++++
 surefire-grouper/pom.xml                           |  26 ++++
 surefire-logger-api/pom.xml                        |  52 +++++++
 .../surefire/log/api/ConsoleLoggerDecorator.java   |   2 +-
 .../surefire/log/api/ConsoleLoggerUtilsTest.java   |  64 +++++++++
 .../plugin/surefire/log/api}/JUnit4SuiteTest.java  |  15 +-
 .../maven/plugin/surefire/log/api/LevelTest.java   |  73 ++++++++++
 .../maven/plugin/surefire/log/api/LoggersTest.java | 139 ++++++++++++++++++
 surefire-providers/common-java5/pom.xml            |  34 ++++-
 surefire-providers/common-junit3/pom.xml           |  41 ++++++
 surefire-providers/common-junit4/pom.xml           |  41 ++++++
 surefire-providers/common-junit48/pom.xml          |  31 ++++
 .../surefire/common/junit48/JUnit4SuiteTest.java   |  18 ++-
 surefire-providers/surefire-junit-platform/pom.xml |  24 ++++
 .../surefire/junitplatform/JUnit47SuiteTest.java   |  21 ++-
 surefire-providers/surefire-junit3/pom.xml         |  41 ++++++
 surefire-providers/surefire-junit4/pom.xml         |  44 ++++++
 .../maven/surefire/junit4/JUnit4ProviderTest.java  |   6 +-
 .../maven/surefire/junit4}/JUnit4SuiteTest.java    |  18 +--
 surefire-providers/surefire-junit47/pom.xml        |  31 ++++
 .../maven/surefire/junitcore/JUnit47SuiteTest.java |  40 +++---
 surefire-providers/surefire-testng-utils/pom.xml   |  26 ++++
 surefire-providers/surefire-testng/pom.xml         |  26 ++++
 surefire-report-parser/pom.xml                     |  24 ++++
 .../plugins/surefire/report/JUnit4SuiteTest.java   |  20 ++-
 52 files changed, 1430 insertions(+), 450 deletions(-)

diff --git a/Jenkinsfile b/Jenkinsfile
index 3f96cad..b2d8023 100644
--- a/Jenkinsfile
+++ b/Jenkinsfile
@@ -68,9 +68,6 @@ oses.eachWithIndex { osMapping, indexOfOs ->
                         boolean first = indexOfOs == 0 && indexOfMaven == 0 && indexOfJdk == 0
                         def failsafeItPort = 8000 + 100 * indexOfMaven + 10 * indexOfJdk
                         def allOptions = options + ["-Dfailsafe-integration-test-port=${failsafeItPort}", "-Dfailsafe-integration-test-stop-port=${1 + failsafeItPort}"]
-                        if (jdk > 7) {
-                            allOptions += ['-DpowermockVersion=2.0.0', '-Denforcer.skip=true']
-                        }
                         ws(dir: "${os == 'windows' ? "${TEMP}\\${BUILD_TAG}" : pwd()}") {
                             buildProcess(stageKey, jdkName, jdkTestName, mvnName, first ? goalsDepl : goals, allOptions, mavenOpts, first)
                         }
diff --git a/maven-failsafe-plugin/pom.xml b/maven-failsafe-plugin/pom.xml
index 31dcfbf..9928f11 100644
--- a/maven-failsafe-plugin/pom.xml
+++ b/maven-failsafe-plugin/pom.xml
@@ -86,6 +86,12 @@
             <artifactId>mockito-core</artifactId>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>org.jacoco</groupId>
+            <artifactId>org.jacoco.agent</artifactId>
+            <classifier>runtime</classifier>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 
     <build>
@@ -113,6 +119,29 @@
                 </executions>
             </plugin>
             <plugin>
+                <groupId>org.jacoco</groupId>
+                <artifactId>jacoco-maven-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>jacoco-agent</id>
+                        <goals>
+                            <goal>prepare-agent</goal>
+                        </goals>
+                    </execution>
+                    <execution>
+                        <!--todo remove-->
+                        <id>jacoco-report</id>
+                        <phase>prepare-package</phase>
+                        <goals>
+                            <goal>report</goal>
+                        </goals>
+                    </execution>
+                </executions>
+                <configuration>
+                    <propertyName>jacoco.agent</propertyName>
+                </configuration>
+            </plugin>
+            <plugin>
                 <artifactId>maven-surefire-plugin</artifactId>
                 <dependencies>
                     <dependency>
@@ -122,6 +151,7 @@
                     </dependency>
                 </dependencies>
                 <configuration>
+                    <argLine>${jvm.args.tests} ${jacoco.agent}</argLine>
                     <includes>
                         <include>**/JUnit4SuiteTest.java</include>
                     </includes>
diff --git a/maven-failsafe-plugin/src/test/java/org/apache/maven/plugin/failsafe/IntegrationTestMojoTest.java b/maven-failsafe-plugin/src/test/java/org/apache/maven/plugin/failsafe/IntegrationTestMojoTest.java
index 8414d6b..5e008aa 100644
--- a/maven-failsafe-plugin/src/test/java/org/apache/maven/plugin/failsafe/IntegrationTestMojoTest.java
+++ b/maven-failsafe-plugin/src/test/java/org/apache/maven/plugin/failsafe/IntegrationTestMojoTest.java
@@ -1 +1 @@
-package org.apache.maven.plugin.failsafe;

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.DefaultArtifact;
import org.apache.maven.artifact.versioning.Invali
 dVersionSpecificationException;
import org.apache.maven.project.MavenProject;
import org.junit.Before;
import org.junit.Test;

import java.io.File;
import java.io.IOException;

import static org.apache.maven.artifact.versioning.VersionRange.createFromVersionSpec;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import static org.fest.assertions.Assertions.assertThat;

/**
 * @since 2.20
 */
public class IntegrationTestMojoTest
{
    private IntegrationTestMojo mojo;

    @Before
    public void init() throws InvalidVersionSpecificationException, IOException
    {
        Artifact artifact = new DefaultArtifact( "g", "a", createFromVersionSpec( "1.0" ), "compile", "jar", "", null );
        artifact.setFile( new File( "./target/tmp/a-1.0.jar" ) );
        new File( "./target/tmp" ).mkdir();
        artifact.getFile().createNewFile();
        mojo = spy( IntegrationTestMojo.class );
        MavenProject project = mo
 ck( MavenProject.class );
        when( project.getArtifact() ).thenReturn( artifact );
        when( mojo.getProject() ).thenReturn( project );
    }

    @Test
    public void shouldBeJar()
    {
        mojo.setDefaultClassesDirectory( new File( "./target/classes" ) );
        File binaries = mojo.getClassesDirectory();
        assertThat( binaries.getName() ).isEqualTo( "a-1.0.jar" );
    }

    @Test
    public void shouldBeAnotherJar()
    {
        mojo.setClassesDirectory( new File( "./target/another-1.0.jar" ) );
        mojo.setDefaultClassesDirectory( new File( "./target/classes" ) );
        File binaries = mojo.getClassesDirectory();
        assertThat( binaries.getName() ).isEqualTo( "another-1.0.jar" );
    }

    @Test
    public void shouldBeClasses()
    {
        mojo.setClassesDirectory( new File( "./target/classes" ) );
        mojo.setDefaultClassesDirectory( new File( "./target/classes" ) );
        File binaries = mojo.getClassesDirectory();
        assertTha
 t( binaries.getName() ).isEqualTo( "classes" );
    }
}
\ No newline at end of file
+package org.apache.maven.plugin.failsafe;

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.DefaultArtifact;
import org.apache.maven.artifact.versioning.Invali
 dVersionSpecificationException;
import org.apache.maven.project.MavenProject;
import org.junit.Before;
import org.junit.Test;

import java.io.File;
import java.io.IOException;

import static org.apache.maven.artifact.versioning.VersionRange.createFromVersionSpec;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.fest.assertions.Assertions.assertThat;

/**
 * @since 2.20
 */
public class IntegrationTestMojoTest
{
    private IntegrationTestMojo mojo;

    @Before
    public void init() throws InvalidVersionSpecificationException, IOException
    {
        Artifact artifact = new DefaultArtifact( "g", "a", createFromVersionSpec( "1.0" ), "compile", "jar", "", null );
        artifact.setFile( new File( "./target/tmp/a-1.0.jar" ) );
        new File( "./target/tmp" ).mkdir();
        artifact.getFile().createNewFile();
        mojo = new IntegrationTestMojo();
        MavenProject project = mock( MavenProject.class );
        when( projec
 t.getArtifact() ).thenReturn( artifact );
        mojo.setProject( project );
    }

    @Test
    public void shouldBeJar()
    {
        mojo.setDefaultClassesDirectory( new File( "./target/classes" ) );
        File binaries = mojo.getClassesDirectory();
        assertThat( binaries.getName() ).isEqualTo( "a-1.0.jar" );
    }

    @Test
    public void shouldBeAnotherJar()
    {
        mojo.setClassesDirectory( new File( "./target/another-1.0.jar" ) );
        mojo.setDefaultClassesDirectory( new File( "./target/classes" ) );
        File binaries = mojo.getClassesDirectory();
        assertThat( binaries.getName() ).isEqualTo( "another-1.0.jar" );
    }

    @Test
    public void shouldBeClasses()
    {
        mojo.setClassesDirectory( new File( "./target/classes" ) );
        mojo.setDefaultClassesDirectory( new File( "./target/classes" ) );
        File binaries = mojo.getClassesDirectory();
        assertThat( binaries.getName() ).isEqualTo( "classes" );
    }
}
\ No newline at end of file
diff --git a/maven-surefire-common/pom.xml b/maven-surefire-common/pom.xml
index 18fed62..ff7eb97 100644
--- a/maven-surefire-common/pom.xml
+++ b/maven-surefire-common/pom.xml
@@ -120,17 +120,60 @@
             <artifactId>powermock-api-mockito2</artifactId>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>org.jacoco</groupId>
+            <artifactId>org.jacoco.agent</artifactId>
+            <classifier>runtime</classifier>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 
     <build>
         <plugins>
             <plugin>
+                <artifactId>maven-dependency-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>build-test-classpath</id>
+                        <phase>generate-sources</phase>
+                        <goals>
+                            <goal>build-classpath</goal>
+                        </goals>
+                        <configuration>
+                            <includeScope>test</includeScope>
+                            <outputFile>target/test-classpath/cp.txt</outputFile>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.jacoco</groupId>
+                <artifactId>jacoco-maven-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>jacoco-instrumentation</id>
+                        <goals>
+                            <goal>instrument</goal>
+                        </goals>
+                    </execution>
+                    <execution>
+                        <id>restore-classes</id>
+                        <goals>
+                            <goal>restore-instrumented-classes</goal>
+                        </goals>
+                    </execution>
+                    <execution>
+                        <!--todo remove-->
+                        <id>jacoco-report</id>
+                        <phase>prepare-package</phase>
+                        <goals>
+                            <goal>report</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
                 <artifactId>maven-surefire-plugin</artifactId>
-                <configuration>
-                    <includes>
-                        <include>**/JUnit4SuiteTest.java</include>
-                    </includes>
-                </configuration>
                 <dependencies>
                     <dependency>
                         <groupId>org.apache.maven.surefire</groupId>
@@ -138,6 +181,15 @@
                         <version>3.0.0-M3</version> <!-- ${shadedVersion}, but resolved due to https://issues.apache.org/jira/browse/MRELEASE-799 -->
                     </dependency>
                 </dependencies>
+                <configuration>
+                    <argLine>${jvm.args.tests}</argLine>
+                    <includes>
+                        <include>**/JUnit4SuiteTest.java</include>
+                    </includes>
+                    <systemPropertyVariables>
+                        <jacoco-agent.destfile>${project.build.directory}/jacoco.exec</jacoco-agent.destfile>
+                    </systemPropertyVariables>
+                </configuration>
             </plugin>
             <plugin>
                 <artifactId>maven-shade-plugin</artifactId>
diff --git a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/AbstractSurefireMojoJava7PlusTest.java b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/AbstractSurefireMojoJava7PlusTest.java
index 7770ab1..b178d64 100644
--- a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/AbstractSurefireMojoJava7PlusTest.java
+++ b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/AbstractSurefireMojoJava7PlusTest.java
@@ -39,6 +39,7 @@ import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
+import org.powermock.core.classloader.annotations.PowerMockIgnore;
 import org.powermock.core.classloader.annotations.PrepareForTest;
 import org.powermock.modules.junit4.PowerMockRunner;
 
@@ -68,6 +69,7 @@ import static org.powermock.reflect.Whitebox.invokeMethod;
  */
 @RunWith( PowerMockRunner.class )
 @PrepareForTest( { AbstractSurefireMojo.class, ResolvePathsRequest.class } )
+@PowerMockIgnore( { "org.jacoco.agent.rt.*", "com.vladium.emma.rt.*" } )
 public class AbstractSurefireMojoJava7PlusTest
 {
     @Mock
diff --git a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/AbstractSurefireMojoTest.java b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/AbstractSurefireMojoTest.java
index c71001b..cec6760 100644
--- a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/AbstractSurefireMojoTest.java
+++ b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/AbstractSurefireMojoTest.java
@@ -50,6 +50,7 @@ import org.mockito.ArgumentMatchers;
 import org.mockito.Mock;
 import org.mockito.invocation.InvocationOnMock;
 import org.mockito.stubbing.Answer;
+import org.powermock.core.classloader.annotations.PowerMockIgnore;
 import org.powermock.core.classloader.annotations.PrepareForTest;
 import org.powermock.modules.junit4.PowerMockRunner;
 
@@ -90,6 +91,7 @@ import static org.powermock.reflect.Whitebox.invokeMethod;
  */
 @RunWith( PowerMockRunner.class )
 @PrepareForTest( AbstractSurefireMojo.class )
+@PowerMockIgnore( { "org.jacoco.agent.rt.*", "com.vladium.emma.rt.*" } )
 public class AbstractSurefireMojoTest
 {
     @Mock
@@ -1576,7 +1578,7 @@ public class AbstractSurefireMojoTest
     }
 
     public static class Mojo
-            extends AbstractSurefireMojo
+            extends AbstractSurefireMojo implements SurefireReportParameters
     {
         private JUnitPlatformProviderInfo createJUnitPlatformProviderInfo( Artifact providerArtifact,
                                                                            TestClassPath testClasspathWrapper )
@@ -1639,6 +1641,18 @@ public class AbstractSurefireMojoTest
         }
 
         @Override
+        public boolean isTestFailureIgnore()
+        {
+            return false;
+        }
+
+        @Override
+        public void setTestFailureIgnore( boolean testFailureIgnore )
+        {
+
+        }
+
+        @Override
         public File getBasedir()
         {
             return null;
diff --git a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/MojoMocklessTest.java b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/MojoMocklessTest.java
index f8ba15f..ed846aa 100644
--- a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/MojoMocklessTest.java
+++ b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/MojoMocklessTest.java
@@ -27,6 +27,7 @@ import org.apache.maven.artifact.versioning.VersionRange;
 import org.apache.maven.plugin.MojoFailureException;
 import org.apache.maven.surefire.suite.RunResult;
 import org.apache.maven.surefire.util.DefaultScanResult;
+import org.apache.maven.toolchain.Toolchain;
 import org.junit.Test;
 
 import java.io.File;
@@ -38,10 +39,77 @@ import java.util.zip.ZipOutputStream;
 import static java.util.Arrays.asList;
 import static java.util.Collections.singletonList;
 import static org.fest.assertions.Assertions.assertThat;
+import static org.junit.Assert.fail;
+import static org.powermock.reflect.Whitebox.setInternalState;
 
 public class MojoMocklessTest
 {
     @Test
+    public void testForkMode()
+    {
+        AbstractSurefireMojo surefirePlugin = new Mojo( null, null );
+        setInternalState( surefirePlugin, "toolchain", new MyToolChain() );
+        setInternalState( surefirePlugin, "forkMode", "never" );
+        assertThat( surefirePlugin.getEffectiveForkMode() )
+                .isEqualTo( "once" );
+    }
+
+    @Test
+    public void testForkCountComputation()
+    {
+        AbstractSurefireMojo surefirePlugin = new Mojo( null, null );
+        assertConversionFails( surefirePlugin, "nothing" );
+
+        assertConversionFails( surefirePlugin, "5,0" );
+        assertConversionFails( surefirePlugin, "5.0" );
+        assertConversionFails( surefirePlugin, "5,0C" );
+        assertConversionFails( surefirePlugin, "5.0CC" );
+
+        assertForkCount( surefirePlugin, 5, "5" );
+
+        int availableProcessors = Runtime.getRuntime().availableProcessors();
+        assertForkCount( surefirePlugin, 3 * availableProcessors, "3C" );
+        assertForkCount( surefirePlugin, (int) ( 2.5 * availableProcessors ), "2.5C" );
+        assertForkCount( surefirePlugin, availableProcessors, "1.0001 C" );
+        assertForkCount( surefirePlugin, 1, 1d / ( (double) availableProcessors + 1 ) + "C" );
+        assertForkCount( surefirePlugin, 0, "0 C" );
+    }
+
+    private static void assertForkCount( AbstractSurefireMojo surefirePlugin, int expected, String value )
+    {
+        assertThat( surefirePlugin.convertWithCoreCount( value ) )
+                .isEqualTo( expected );
+    }
+
+    private static void assertConversionFails( AbstractSurefireMojo surefirePlugin, String value )
+    {
+        try
+        {
+            surefirePlugin.convertWithCoreCount( value );
+        }
+        catch ( NumberFormatException e )
+        {
+            return;
+        }
+        fail( "Expected NumberFormatException when converting " + value );
+    }
+
+    private static class MyToolChain implements Toolchain
+    {
+        @Override
+        public String getType()
+        {
+            return null;
+        }
+
+        @Override
+        public String findTool( String s )
+        {
+            return null;
+        }
+    }
+
+    @Test
     public void scanDependenciesShouldReturnNull()
             throws MojoFailureException
     {
diff --git a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/SurefireHelperTest.java b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/SurefireHelperTest.java
index e5f8eb8..9541d3a 100644
--- a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/SurefireHelperTest.java
+++ b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/SurefireHelperTest.java
@@ -19,6 +19,9 @@ package org.apache.maven.plugin.surefire;
  * under the License.
  */
 
+import org.apache.maven.plugin.MojoFailureException;
+import org.apache.maven.plugin.surefire.AbstractSurefireMojoTest.Mojo;
+import org.apache.maven.surefire.suite.RunResult;
 import org.junit.Test;
 
 import java.io.File;
@@ -29,7 +32,9 @@ import static java.util.Collections.addAll;
 import static java.util.Collections.singleton;
 import static org.apache.commons.lang3.SystemUtils.IS_OS_WINDOWS;
 import static org.apache.maven.plugin.surefire.SurefireHelper.escapeToPlatformPath;
+import static org.apache.maven.plugin.surefire.SurefireHelper.reportExecution;
 import static org.fest.assertions.Assertions.assertThat;
+import static org.junit.Assert.fail;
 import static org.junit.Assume.assumeTrue;
 
 /**
@@ -108,4 +113,46 @@ public class SurefireHelperTest
         escaped = escapeToPlatformPath( path );
         assertThat( escaped ).isEqualTo( root + "\\" + pathToJar );
     }
+
+    @Test
+    public void shouldHandleFailIfNoTests() throws Exception
+    {
+        RunResult summary = new RunResult( 0, 0, 0, 0 );
+        try
+        {
+            Mojo plugin = new Mojo();
+            plugin.setFailIfNoTests( true );
+            reportExecution( plugin, summary, null, null );
+        }
+        catch ( MojoFailureException e )
+        {
+            assertThat( e.getLocalizedMessage() )
+                    .isEqualTo( "No tests were executed!  (Set -DfailIfNoTests=false to ignore this error.)" );
+            return;
+        }
+        fail( "Expected MojoFailureException with message "
+                + "'No tests were executed!  (Set -DfailIfNoTests=false to ignore this error.)'" );
+    }
+
+    @Test
+    public void shouldHandleTestFailure() throws Exception
+    {
+        RunResult summary = new RunResult( 1, 0, 1, 0 );
+        try
+        {
+            reportExecution( new Mojo(), summary, null, null );
+        }
+        catch ( MojoFailureException e )
+        {
+            assertThat( e.getLocalizedMessage() )
+                    .isEqualTo( "There are test failures.\n\nPlease refer to null "
+                            + "for the individual test results.\nPlease refer to dump files (if any exist) "
+                            + "[date].dump, [date]-jvmRun[N].dump and [date].dumpstream." );
+            return;
+        }
+        fail( "Expected MojoFailureException with message "
+                + "'There are test failures.\n\nPlease refer to null "
+                + "for the individual test results.\nPlease refer to dump files (if any exist) "
+                + "[date].dump, [date]-jvmRun[N].dump and [date].dumpstream.'");
+    }
 }
diff --git a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/DefaultForkConfigurationTest.java b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/DefaultForkConfigurationTest.java
index 6bedab9..a8f6c69 100644
--- a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/DefaultForkConfigurationTest.java
+++ b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/DefaultForkConfigurationTest.java
@@ -31,6 +31,7 @@ import org.apache.maven.surefire.booter.SurefireBooterForkException;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.powermock.core.classloader.annotations.PowerMockIgnore;
 import org.powermock.core.classloader.annotations.PrepareForTest;
 import org.powermock.modules.junit4.PowerMockRunner;
 
@@ -58,6 +59,7 @@ import static org.powermock.reflect.Whitebox.invokeMethod;
  */
 @RunWith( PowerMockRunner.class )
 @PrepareForTest( { DefaultForkConfiguration.class, Relocator.class } )
+@PowerMockIgnore( { "org.jacoco.agent.rt.*", "com.vladium.emma.rt.*" } )
 public class DefaultForkConfigurationTest
 {
     private Classpath booterClasspath;
diff --git a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/JarManifestForkConfigurationTest.java b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/JarManifestForkConfigurationTest.java
index 08b3030..8f8cd8f 100644
--- a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/JarManifestForkConfigurationTest.java
+++ b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/JarManifestForkConfigurationTest.java
@@ -53,6 +53,7 @@ import static org.powermock.api.mockito.PowerMockito.when;
 
 import org.mockito.invocation.InvocationOnMock;
 import org.mockito.stubbing.Answer;
+import org.powermock.core.classloader.annotations.PowerMockIgnore;
 import org.powermock.core.classloader.annotations.PrepareForTest;
 import org.powermock.modules.junit4.PowerMockRunner;
 
@@ -61,6 +62,7 @@ import org.powermock.modules.junit4.PowerMockRunner;
  */
 @RunWith( PowerMockRunner.class )
 @PrepareForTest( { JarManifestForkConfiguration.class, InPluginProcessDumpSingleton.class } )
+@PowerMockIgnore( { "org.jacoco.agent.rt.*", "com.vladium.emma.rt.*" } )
 public class JarManifestForkConfigurationTest
 {
     private static final File TMP = newTemporaryFolder();
diff --git a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/report/TestSetStatsTest.java b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/report/TestSetStatsTest.java
index 7fdb51d..7aac381 100644
--- a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/report/TestSetStatsTest.java
+++ b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/report/TestSetStatsTest.java
@@ -23,6 +23,7 @@ import org.apache.maven.surefire.report.ReportEntry;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
+import org.powermock.core.classloader.annotations.PowerMockIgnore;
 import org.powermock.modules.junit4.PowerMockRunner;
 
 import static org.apache.maven.shared.utils.logging.MessageUtils.buffer;
@@ -36,6 +37,7 @@ import static org.mockito.Mockito.when;
  * tests for {@link TestSetStats}.
  */
 @RunWith( PowerMockRunner.class )
+@PowerMockIgnore( { "org.jacoco.agent.rt.*", "com.vladium.emma.rt.*" } )
 public class TestSetStatsTest
 {
     @Mock
diff --git a/maven-surefire-common/src/test/java/org/apache/maven/surefire/extensions/StatelessTestsetInfoReporterTest.java b/maven-surefire-common/src/test/java/org/apache/maven/surefire/extensions/StatelessTestsetInfoReporterTest.java
index 0ce6f7d..7967268 100644
--- a/maven-surefire-common/src/test/java/org/apache/maven/surefire/extensions/StatelessTestsetInfoReporterTest.java
+++ b/maven-surefire-common/src/test/java/org/apache/maven/surefire/extensions/StatelessTestsetInfoReporterTest.java
@@ -32,6 +32,7 @@ import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
+import org.powermock.core.classloader.annotations.PowerMockIgnore;
 import org.powermock.modules.junit4.PowerMockRunner;
 
 import java.io.File;
@@ -54,6 +55,7 @@ import static org.powermock.reflect.Whitebox.getInternalState;
  * tests for {@link DefaultStatelessTestsetInfoReporter} and {@link JUnit5StatelessTestsetInfoReporter}.
  */
 @RunWith( PowerMockRunner.class )
+@PowerMockIgnore( { "org.jacoco.agent.rt.*", "com.vladium.emma.rt.*" } )
 public class StatelessTestsetInfoReporterTest
 {
     @Mock
diff --git a/maven-surefire-plugin/pom.xml b/maven-surefire-plugin/pom.xml
index ac34a2b..5a1261f 100644
--- a/maven-surefire-plugin/pom.xml
+++ b/maven-surefire-plugin/pom.xml
@@ -86,7 +86,33 @@
                 </executions>
             </plugin>
             <plugin>
+                <groupId>org.jacoco</groupId>
+                <artifactId>jacoco-maven-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>jacoco-agent</id>
+                        <goals>
+                            <goal>prepare-agent</goal>
+                        </goals>
+                    </execution>
+                    <execution>
+                        <!--todo remove-->
+                        <id>jacoco-report</id>
+                        <phase>prepare-package</phase>
+                        <goals>
+                            <goal>report</goal>
+                        </goals>
+                    </execution>
+                </executions>
+                <configuration>
+                    <propertyName>jacoco.agent</propertyName>
+                </configuration>
+            </plugin>
+            <plugin>
                 <artifactId>maven-surefire-plugin</artifactId>
+                <configuration>
+                    <argLine>${jvm.args.tests} ${jacoco.agent}</argLine>
+                </configuration>
                 <dependencies>
                     <dependency>
                         <groupId>org.apache.maven.surefire</groupId>
diff --git a/maven-surefire-plugin/src/test/java/org/apache/maven/plugin/surefire/SurefirePluginTest.java b/maven-surefire-plugin/src/test/java/org/apache/maven/plugin/surefire/SurefirePluginTest.java
index 4cbbf00..6d7b4a3 100644
--- a/maven-surefire-plugin/src/test/java/org/apache/maven/plugin/surefire/SurefirePluginTest.java
+++ b/maven-surefire-plugin/src/test/java/org/apache/maven/plugin/surefire/SurefirePluginTest.java
@@ -18,99 +18,70 @@ package org.apache.maven.plugin.surefire;
  * under the License.
  */
 
-
-import java.lang.reflect.Field;
-import org.apache.maven.toolchain.Toolchain;
-
 import junit.framework.TestCase;
+import org.apache.maven.plugin.MojoFailureException;
+import org.apache.maven.surefire.suite.RunResult;
 
-public class SurefirePluginTest
-    extends TestCase
-{
-
-    public void testForkMode()
-        throws NoSuchFieldException, IllegalAccessException
-    {
-        SurefirePlugin surefirePlugin = new SurefirePlugin();
-        setFieldValue( surefirePlugin, "toolchain", new MyToolChain() );
-        setFieldValue( surefirePlugin, "forkMode", "never" );
-        assertEquals( "once", surefirePlugin.getEffectiveForkMode() );
-    }
+import static org.fest.assertions.Assertions.assertThat;
 
-    public void testForkCountComputation()
+public class SurefirePluginTest extends TestCase
+{
+    public void testDefaultIncludes()
     {
-        SurefirePlugin surefirePlugin = new SurefirePlugin();
-        assertConversionFails( surefirePlugin, "nothing" );
-
-        assertConversionFails( surefirePlugin, "5,0" );
-        assertConversionFails( surefirePlugin, "5.0" );
-        assertConversionFails( surefirePlugin, "5,0C" );
-        assertConversionFails( surefirePlugin, "5.0CC" );
-
-        assertForkCount( surefirePlugin, 5, "5" );
-
-        int availableProcessors = Runtime.getRuntime().availableProcessors();
-        assertForkCount( surefirePlugin, 3*availableProcessors, "3C" );
-        assertForkCount( surefirePlugin, (int) ( 2.5*availableProcessors ), "2.5C" );
-        assertForkCount( surefirePlugin, availableProcessors, "1.0001 C" );
-        assertForkCount( surefirePlugin, 1, 1d / ( (double) availableProcessors + 1 ) + "C" );
-        assertForkCount( surefirePlugin, 0, "0 C" );
+        assertThat( new SurefirePlugin().getDefaultIncludes() )
+                .containsOnly( "**/Test*.java", "**/*Test.java", "**/*Tests.java", "**/*TestCase.java" );
     }
 
-    private void assertForkCount( SurefirePlugin surefirePlugin, int expected, String value )
+    public void testReportSchemaLocation()
     {
-        assertEquals( expected, surefirePlugin.convertWithCoreCount( value ));
+        assertThat( new SurefirePlugin().getReportSchemaLocation() )
+            .isEqualTo( "https://maven.apache.org/surefire/maven-surefire-plugin/xsd/surefire-test-report-3.0.xsd" );
     }
 
-    private void assertConversionFails( SurefirePlugin surefirePlugin, String value )
+    public void testFailIfNoTests() throws Exception
     {
-        try {
-            surefirePlugin.convertWithCoreCount( value );
-        } catch (NumberFormatException nfe)
+        RunResult runResult = new RunResult( 0, 0, 0, 0 );
+        try
         {
-            return;
+            SurefirePlugin plugin = new SurefirePlugin();
+            plugin.setFailIfNoTests( true );
+            plugin.handleSummary( runResult, null );
         }
-        fail( "Expected NumberFormatException when converting " + value );
-    }
-
-    private void setFieldValue( SurefirePlugin plugin, String fieldName, Object value )
-        throws NoSuchFieldException, IllegalAccessException
-    {
-        Field field = findField( plugin.getClass(), fieldName );
-        field.setAccessible( true );
-        field.set( plugin, value );
-
-    }
-
-    private Field findField( Class clazz, String fieldName )
-    {
-        while ( clazz != null )
+        catch ( MojoFailureException e )
         {
-            try
-            {
-                return clazz.getDeclaredField( fieldName );
-            }
-            catch ( NoSuchFieldException e )
-            {
-                clazz = clazz.getSuperclass();
-            }
+            assertThat( e.getLocalizedMessage() )
+                    .isEqualTo( "No tests were executed!  (Set -DfailIfNoTests=false to ignore this error.)" );
+            return;
         }
-        throw new IllegalArgumentException( "Field not found" );
+        fail( "Expected MojoFailureException with message "
+                + "'No tests were executed!  (Set -DfailIfNoTests=false to ignore this error.)'" );
     }
 
-    private class MyToolChain
-        implements Toolchain
+    public void testTestFailure() throws Exception
     {
-        @Override
-        public String getType()
+        RunResult runResult = new RunResult( 1, 0, 1, 0 );
+        try
         {
-            return null;
+            SurefirePlugin plugin = new SurefirePlugin();
+            plugin.handleSummary( runResult, null );
         }
-
-        @Override
-        public String findTool( String s )
+        catch ( MojoFailureException e )
         {
-            return null;
+            assertThat( e.getLocalizedMessage() )
+                    .isEqualTo( "There are test failures.\n\nPlease refer to null "
+                            + "for the individual test results.\nPlease refer to dump files (if any exist) "
+                            + "[date].dump, [date]-jvmRun[N].dump and [date].dumpstream." );
+            return;
         }
+        fail( "Expected MojoFailureException with message "
+                + "'There are test failures.\n\nPlease refer to null "
+                + "for the individual test results.\nPlease refer to dump files (if any exist) "
+                + "[date].dump, [date]-jvmRun[N].dump and [date].dumpstream.'");
+    }
+
+    public void testPluginName()
+    {
+        assertThat( new SurefirePlugin().getPluginName() )
+                .isEqualTo( "surefire" );
     }
 }
diff --git a/maven-surefire-report-plugin/pom.xml b/maven-surefire-report-plugin/pom.xml
index cf941ce..5f855d0 100644
--- a/maven-surefire-report-plugin/pom.xml
+++ b/maven-surefire-report-plugin/pom.xml
@@ -179,8 +179,35 @@
                 </executions>
             </plugin>
             <plugin>
+                <groupId>org.jacoco</groupId>
+                <artifactId>jacoco-maven-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>jacoco-agent</id>
+                        <goals>
+                            <goal>prepare-agent</goal>
+                        </goals>
+                    </execution>
+                    <execution>
+                        <!--todo remove-->
+                        <id>jacoco-report</id>
+                        <phase>prepare-package</phase>
+                        <goals>
+                            <goal>report</goal>
+                        </goals>
+                    </execution>
+                </executions>
+                <configuration>
+                    <propertyName>jacoco.agent</propertyName>
+                </configuration>
+            </plugin>
+            <plugin>
                 <artifactId>maven-surefire-plugin</artifactId>
                 <configuration>
+                    <argLine>${jvm.args.tests} ${jacoco.agent}</argLine>
+                    <includes>
+                        <include>**/JUnit4SuiteTest.java</include>
+                    </includes>
                     <classpathDependencyExcludes>
                         <classpathDependencyExclude>org.fusesource.jansi:jansi</classpathDependencyExclude>
                     </classpathDependencyExcludes>
diff --git a/surefire-report-parser/src/test/java/org/apache/maven/plugins/surefire/report/JUnit4SuiteTest.java b/maven-surefire-report-plugin/src/test/java/org/apache/maven/plugins/surefire/report/JUnit4SuiteTest.java
similarity index 70%
copy from surefire-report-parser/src/test/java/org/apache/maven/plugins/surefire/report/JUnit4SuiteTest.java
copy to maven-surefire-report-plugin/src/test/java/org/apache/maven/plugins/surefire/report/JUnit4SuiteTest.java
index 142ca9d..5ab3ee1 100644
--- a/surefire-report-parser/src/test/java/org/apache/maven/plugins/surefire/report/JUnit4SuiteTest.java
+++ b/maven-surefire-report-plugin/src/test/java/org/apache/maven/plugins/surefire/report/JUnit4SuiteTest.java
@@ -21,26 +21,24 @@ package org.apache.maven.plugins.surefire.report;
 
 import junit.framework.JUnit4TestAdapter;
 import junit.framework.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Suite;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
 
 /**
  * Adapt the JUnit4 tests which use only annotations to the JUnit3 test suite.
  *
  * @author Tibor Digana (tibor17)
- * @since 2.21.0
+ * @since 3.0.0-M4
  */
-@Suite.SuiteClasses( {
-        ReportTestCaseTest.class,
-        ReportTestSuiteTest.class,
-        SurefireReportParserTest.class,
-        TestSuiteXmlParserTest.class
-} )
-@RunWith( Suite.class )
-public class JUnit4SuiteTest
+public class JUnit4SuiteTest extends TestCase
 {
     public static Test suite()
     {
-        return new JUnit4TestAdapter( JUnit4SuiteTest.class );
+        TestSuite suite = new TestSuite();
+        suite.addTest( new JUnit4TestAdapter( Surefire597Test.class ) );
+        suite.addTest( new JUnit4TestAdapter( SurefireSchemaValidationTest.class ) );
+        suite.addTestSuite( Surefire1183Test.class );
+        suite.addTestSuite(  SurefireReportMojoTest.class);
+        return suite;
     }
 }
diff --git a/pom.xml b/pom.xml
index ffdfee6..113e0f7 100644
--- a/pom.xml
+++ b/pom.xml
@@ -94,7 +94,8 @@
     <doxiaSitetoolsVersion>1.8.1</doxiaSitetoolsVersion>
     <!-- maven-shared-utils:3.2.0+ another behavior - broke Surefire performance - end of subprocess notification not arrived in ForkStarter -->
     <mavenSharedUtilsVersion>3.1.0</mavenSharedUtilsVersion>
-    <powermockVersion>2.0.0-RC.1</powermockVersion>
+    <powermockVersion>2.0.2</powermockVersion>
+    <jacocoVersion>0.8.4</jacocoVersion>
     <maven.surefire.scm.devConnection>scm:git:https://gitbox.apache.org/repos/asf/maven-surefire.git</maven.surefire.scm.devConnection>
     <maven.site.path>surefire-archives/surefire-LATEST</maven.site.path>
     <!-- Override with Jigsaw JRE 9 -->
@@ -331,7 +332,7 @@
       <dependency>
         <groupId>org.mockito</groupId>
         <artifactId>mockito-core</artifactId>
-        <version>2.21.0</version>
+        <version>2.23.4</version>
         <exclusions>
           <exclusion>
             <groupId>org.hamcrest</groupId>
@@ -364,6 +365,11 @@
         <version>${powermockVersion}</version>
         <scope>compile</scope>
       </dependency>
+      <dependency>
+        <groupId>org.javassist</groupId>
+        <artifactId>javassist</artifactId>
+        <version>3.22.0-GA</version>
+      </dependency>
       <!-- END: PowerMock@Java9 -->
       <dependency>
         <groupId>junit</groupId>
@@ -384,12 +390,19 @@
         <groupId>org.assertj</groupId>
         <artifactId>assertj-core</artifactId>
         <version>3.9.1</version>
+<!--        <version>3.12.2</version>-->
       </dependency>
       <dependency>
         <groupId>com.google.code.findbugs</groupId>
         <artifactId>jsr305</artifactId>
         <version>2.0.3</version>
       </dependency>
+      <dependency>
+        <groupId>org.jacoco</groupId>
+        <artifactId>org.jacoco.agent</artifactId>
+        <classifier>runtime</classifier>
+        <version>${jacocoVersion}</version>
+      </dependency>
     </dependencies>
   </dependencyManagement>
   <dependencies>
@@ -414,13 +427,6 @@
       <artifactId>fest-assert</artifactId>
       <scope>test</scope>
     </dependency>
-    <dependency>
-      <groupId>org.jacoco</groupId>
-      <artifactId>org.jacoco.agent</artifactId>
-      <classifier>runtime</classifier>
-      <version>0.8.3</version>
-      <scope>test</scope>
-    </dependency>
   </dependencies>
 
   <build>
@@ -486,22 +492,6 @@
           <groupId>org.codehaus.mojo</groupId>
           <artifactId>animal-sniffer-maven-plugin</artifactId>
           <version>1.17</version>
-          <executions>
-            <execution>
-              <id>signature-check</id>
-              <goals>
-                <goal>check</goal>
-              </goals>
-              <configuration>
-                <skip>true</skip>
-                <signature>
-                  <groupId>org.codehaus.mojo.signature</groupId>
-                  <artifactId>java17</artifactId>
-                  <version>1.0</version>
-                </signature>
-              </configuration>
-            </execution>
-          </executions>
         </plugin>
         <plugin>
           <artifactId>maven-surefire-plugin</artifactId>
@@ -513,9 +503,6 @@
             <useFile>false</useFile>
             <redirectTestOutputToFile>false</redirectTestOutputToFile>
             <jvm>${jdk.home}/bin/java</jvm>
-            <systemPropertyVariables>
-              <jacoco-agent.destfile>target/jacoco.exec</jacoco-agent.destfile>
-            </systemPropertyVariables>
           </configuration>
         </plugin>
         <plugin>
@@ -538,48 +525,65 @@
         <plugin>
           <groupId>org.jacoco</groupId>
           <artifactId>jacoco-maven-plugin</artifactId>
-          <version>0.8.3</version>
+          <version>${jacocoVersion}</version>
+          <configuration>
+            <!--<append>true</append>
+            <inclNoLocationClasses>true</inclNoLocationClasses>
+            <haltOnFailure>false</haltOnFailure>
+            <jmx>false</jmx>-->
+            <includes>
+              <include>**/failsafe/*</include>
+              <include>**/failsafe/**/*</include>
+              <include>**/surefire/*</include>
+              <include>**/surefire/**/*</include>
+            </includes>
+            <excludes>
+              <exclude>**/HelpMojo.class</exclude>
+              <exclude>**/shadefire/**/*</exclude>
+              <exclude>org/jacoco/**/*</exclude>
+              <exclude>com/vladium/emma/rt/*</exclude>
+            </excludes>
+          </configuration>
         </plugin>
       </plugins>
     </pluginManagement>
     <plugins>
       <plugin>
-        <groupId>org.jacoco</groupId>
-        <artifactId>jacoco-maven-plugin</artifactId>
+        <groupId>org.apache.rat</groupId>
+        <artifactId>apache-rat-plugin</artifactId>
         <executions>
           <execution>
-            <id>instrument</id>
-            <phase>generate-test-resources</phase>
-            <goals>
-              <goal>instrument</goal>
-            </goals>
-          </execution>
-          <execution>
-            <id>restore-classes</id>
-            <goals>
-              <goal>restore-instrumented-classes</goal>
-            </goals>
-          </execution>
-          <execution>
-            <id>jacoco-report</id>
-            <phase>prepare-package</phase>
+            <id>rat-check</id>
             <goals>
-              <goal>report</goal>
+              <goal>check</goal>
             </goals>
+            <configuration>
+              <excludes combine.children="append">
+                <exclude>Jenkinsfile</exclude>
+                <exclude>README.md</exclude>
+                <exclude>.gitignore</exclude>
+                <exclude>.git/**/*</exclude>
+                <exclude>**/.idea</exclude>
+                <exclude>**/.svn/**/*</exclude>
+                <exclude>**/*.iml</exclude>
+                <exclude>**/*.ipr</exclude>
+                <exclude>**/*.iws</exclude>
+                <exclude>**/*.versionsBackup</exclude>
+                <exclude>**/dependency-reduced-pom.xml</exclude>
+                <exclude>.repository/**</exclude> <!-- jenkins with local maven repository -->
+                <exclude>src/test/resources/**/*</exclude>
+                <exclude>src/test/resources/**/*.css</exclude>
+                <exclude>**/*.jj</exclude>
+                <exclude>src/main/resources/META-INF/services/org.apache.maven.surefire.providerapi.SurefireProvider
+                </exclude>
+                <exclude>DEPENDENCIES</exclude>
+                <exclude>.m2/**</exclude>
+                <exclude>.m2</exclude>
+                <exclude>.travis.yml</exclude>
+              </excludes>
+            </configuration>
           </execution>
         </executions>
-        <configuration>
-          <haltOnFailure>false</haltOnFailure>
-          <includes>
-            <include>**/failsafe/*</include>
-            <include>**/failsafe/**/*</include>
-            <include>**/surefire/*</include>
-            <include>**/surefire/**/*</include>
-          </includes>
-          <excludes>
-            <exclude>**/HelpMojo.class</exclude>
-          </excludes>
-        </configuration>
       </plugin>
       <plugin>
         <groupId>org.apache.maven.plugins</groupId>
@@ -638,45 +642,27 @@
       <plugin>
         <groupId>org.codehaus.mojo</groupId>
         <artifactId>animal-sniffer-maven-plugin</artifactId>
-      </plugin>
-      <plugin>
-        <groupId>org.apache.rat</groupId>
-        <artifactId>apache-rat-plugin</artifactId>
         <executions>
           <execution>
-            <id>rat-check</id>
+            <id>signature-check</id>
             <goals>
               <goal>check</goal>
             </goals>
             <configuration>
-              <excludes combine.children="append">
-                <exclude>Jenkinsfile</exclude>
-                <exclude>README.md</exclude>
-                <exclude>.gitignore</exclude>
-                <exclude>.git/**/*</exclude>
-                <exclude>**/.idea</exclude>
-                <exclude>**/.svn/**/*</exclude>
-                <exclude>**/*.iml</exclude>
-                <exclude>**/*.ipr</exclude>
-                <exclude>**/*.iws</exclude>
-                <exclude>**/*.versionsBackup</exclude>
-                <exclude>**/dependency-reduced-pom.xml</exclude>
-                <exclude>.repository/**</exclude> <!-- jenkins with local maven repository -->
-                <exclude>src/test/resources/**/*</exclude>
-                <exclude>src/test/resources/**/*.css</exclude>
-                <exclude>**/*.jj</exclude>
-                <exclude>src/main/resources/META-INF/services/org.apache.maven.surefire.providerapi.SurefireProvider
-                </exclude>
-                <exclude>DEPENDENCIES</exclude>
-                <exclude>.m2/**</exclude>
-                <exclude>.m2</exclude>
-                <exclude>.travis.yml</exclude>
-              </excludes>
+              <signature>
+                <groupId>org.codehaus.mojo.signature</groupId>
+                <artifactId>java17</artifactId>
+                <version>1.0</version>
+              </signature>
             </configuration>
           </execution>
         </executions>
       </plugin>
       <plugin>
+        <groupId>org.jacoco</groupId>
+        <artifactId>jacoco-maven-plugin</artifactId>
+      </plugin>
+      <plugin>
         <artifactId>maven-deploy-plugin</artifactId>
         <configuration>
           <deployAtEnd>true</deployAtEnd>
diff --git a/surefire-api/pom.xml b/surefire-api/pom.xml
index c42041b..e791c9d 100644
--- a/surefire-api/pom.xml
+++ b/surefire-api/pom.xml
@@ -60,8 +60,32 @@
   <build>
     <plugins>
       <plugin>
+        <groupId>org.jacoco</groupId>
+        <artifactId>jacoco-maven-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>jacoco-agent</id>
+            <goals>
+              <goal>prepare-agent</goal>
+            </goals>
+          </execution>
+          <execution>
+            <!--todo remove-->
+            <id>jacoco-report</id>
+            <phase>prepare-package</phase>
+            <goals>
+              <goal>report</goal>
+            </goals>
+          </execution>
+        </executions>
+        <configuration>
+          <propertyName>jacoco.agent</propertyName>
+        </configuration>
+      </plugin>
+      <plugin>
         <artifactId>maven-surefire-plugin</artifactId>
         <configuration>
+          <argLine>${jvm.args.tests} ${jacoco.agent}</argLine>
           <includes>
             <include>**/JUnit4SuiteTest.java</include>
           </includes>
diff --git a/surefire-api/src/test/java/org/apache/maven/JUnit4SuiteTest.java b/surefire-api/src/test/java/org/apache/maven/JUnit4SuiteTest.java
index 63c4490..38f0c48 100644
--- a/surefire-api/src/test/java/org/apache/maven/JUnit4SuiteTest.java
+++ b/surefire-api/src/test/java/org/apache/maven/JUnit4SuiteTest.java
@@ -23,6 +23,7 @@ import junit.framework.JUnit4TestAdapter;
 import junit.framework.Test;
 import org.apache.maven.plugin.surefire.runorder.ThreadedExecutionSchedulerTest;
 import org.apache.maven.surefire.SpecificTestClassFilterTest;
+import org.apache.maven.surefire.booter.CommandReaderTest;
 import org.apache.maven.surefire.booter.ForkedChannelEncoderTest;
 import org.apache.maven.surefire.booter.ForkingRunListenerTest;
 import org.apache.maven.surefire.booter.MasterProcessCommandTest;
@@ -50,6 +51,7 @@ import org.junit.runners.Suite;
  * @since 2.19
  */
 @Suite.SuiteClasses( {
+    CommandReaderTest.class,
     ThreadedExecutionSchedulerTest.class,
     ForkingRunListenerTest.class,
     MasterProcessCommandTest.class,
diff --git a/surefire-booter/src/test/java/org/apache/maven/surefire/booter/CommandReaderTest.java b/surefire-api/src/test/java/org/apache/maven/surefire/booter/CommandReaderTest.java
similarity index 98%
rename from surefire-booter/src/test/java/org/apache/maven/surefire/booter/CommandReaderTest.java
rename to surefire-api/src/test/java/org/apache/maven/surefire/booter/CommandReaderTest.java
index 00d50b4..5168d2b 100644
--- a/surefire-booter/src/test/java/org/apache/maven/surefire/booter/CommandReaderTest.java
+++ b/surefire-api/src/test/java/org/apache/maven/surefire/booter/CommandReaderTest.java
@@ -193,14 +193,14 @@ public class CommandReaderTest
                 Iterator<String> it = reader.getIterableClasses( new ForkedChannelEncoder( nul() ) ).iterator();
                 assertThat( it.next(), is( CommandReaderTest.class.getName() ) );
                 counter.countDown();
-                assertThat( it.next(), is( PropertiesWrapperTest.class.getName() ) );
+                assertThat( it.next(), is( Foo.class.getName() ) );
             }
         };
         FutureTask<Object> futureTask = new FutureTask<>( runnable, null );
         Thread t = new Thread( futureTask );
         t.start();
         counter.await();
-        addTestToPipeline( PropertiesWrapperTest.class.getName() );
+        addTestToPipeline( Foo.class.getName() );
         try
         {
             futureTask.get();
diff --git a/surefire-booter/src/test/java/org/apache/maven/surefire/booter/Foo.java b/surefire-api/src/test/java/org/apache/maven/surefire/booter/Foo.java
similarity index 100%
rename from surefire-booter/src/test/java/org/apache/maven/surefire/booter/Foo.java
rename to surefire-api/src/test/java/org/apache/maven/surefire/booter/Foo.java
diff --git a/surefire-booter/src/test/java/org/apache/maven/surefire/booter/NewClassLoaderRunner.java b/surefire-api/src/test/java/org/apache/maven/surefire/booter/NewClassLoaderRunner.java
similarity index 97%
rename from surefire-booter/src/test/java/org/apache/maven/surefire/booter/NewClassLoaderRunner.java
rename to surefire-api/src/test/java/org/apache/maven/surefire/booter/NewClassLoaderRunner.java
index 2e71dc7..f137598 100644
--- a/surefire-booter/src/test/java/org/apache/maven/surefire/booter/NewClassLoaderRunner.java
+++ b/surefire-api/src/test/java/org/apache/maven/surefire/booter/NewClassLoaderRunner.java
@@ -19,6 +19,7 @@ package org.apache.maven.surefire.booter;
  * under the License.
  */
 
+import org.apache.maven.shared.utils.io.FileUtils;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -45,8 +46,6 @@ import java.util.HashSet;
 import java.util.List;
 
 import static java.io.File.pathSeparator;
-import static java.nio.charset.StandardCharsets.UTF_8;
-import static org.apache.commons.io.FileUtils.readFileToString;
 
 /**
  * JUnit runner testing methods in a separate class loader.
@@ -193,7 +192,7 @@ public class NewClassLoaderRunner
     public static class TestClassLoader
         extends URLClassLoader
     {
-        public TestClassLoader()
+        TestClassLoader()
         {
             super( toClassPath(), null );
         }
@@ -236,7 +235,7 @@ public class NewClassLoaderRunner
             Collection<URL> classPath = new HashSet<>();
             try
             {
-                String[] files = readFileToString( new File( "target/test-classpath/cp.txt" ), UTF_8 )
+                String[] files = FileUtils.fileRead( new File( "target/test-classpath/cp.txt" ), "UTF-8" )
                         .split( pathSeparator );
                 for ( String file : files )
                 {
diff --git a/surefire-api/src/test/java/org/apache/maven/surefire/booter/SurefireReflectorTest.java b/surefire-api/src/test/java/org/apache/maven/surefire/booter/SurefireReflectorTest.java
index 8394e00..facf51b 100644
--- a/surefire-api/src/test/java/org/apache/maven/surefire/booter/SurefireReflectorTest.java
+++ b/surefire-api/src/test/java/org/apache/maven/surefire/booter/SurefireReflectorTest.java
@@ -19,23 +19,39 @@ package org.apache.maven.surefire.booter;
 */
 
 import junit.framework.TestCase;
+import org.apache.maven.surefire.report.ReporterConfiguration;
 import org.apache.maven.surefire.report.ReporterFactory;
 import org.apache.maven.surefire.report.RunListener;
 import org.apache.maven.surefire.suite.RunResult;
+import org.apache.maven.surefire.testset.DirectoryScannerParameters;
+import org.apache.maven.surefire.testset.RunOrderParameters;
+import org.apache.maven.surefire.testset.TestArtifactInfo;
+import org.apache.maven.surefire.testset.TestListResolver;
+import org.apache.maven.surefire.testset.TestRequest;
+import org.apache.maven.surefire.util.RunOrder;
+
+import java.io.File;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
 
 public class SurefireReflectorTest
         extends TestCase
 {
     public void testShouldCreateFactoryWithoutException()
     {
-        ReporterFactory factory = new ReporterFactory() {
+        ReporterFactory factory = new ReporterFactory()
+        {
             @Override
-            public RunListener createReporter() {
+            public RunListener createReporter()
+            {
                 return null;
             }
 
             @Override
-            public RunResult close() {
+            public RunResult close()
+            {
                 return null;
             }
         };
@@ -46,4 +62,105 @@ public class SurefireReflectorTest
         assertNotNull( baseProviderFactory.getReporterFactory() );
         assertSame( factory, baseProviderFactory.getReporterFactory() );
     }
+    public void testSetDirectoryScannerParameters()
+    {
+        SurefireReflector surefireReflector = getReflector();
+        Object foo = getFoo();
+
+        DirectoryScannerParameters directoryScannerParameters =
+                new DirectoryScannerParameters( new File( "ABC" ), new ArrayList<String>(), new ArrayList<String>(),
+                        new ArrayList<String>(), false, "hourly" );
+        surefireReflector.setDirectoryScannerParameters( foo, directoryScannerParameters );
+        assertTrue( isCalled( foo ) );
+
+    }
+
+    public void testRunOrderParameters()
+    {
+        SurefireReflector surefireReflector = getReflector();
+        Object foo = getFoo();
+
+        RunOrderParameters runOrderParameters = new RunOrderParameters( RunOrder.DEFAULT, new File( "." ) );
+        surefireReflector.setRunOrderParameters( foo, runOrderParameters );
+        assertTrue( isCalled( foo ) );
+    }
+
+    public void testTestSuiteDefinition()
+    {
+        SurefireReflector surefireReflector = getReflector();
+        Object foo = getFoo();
+
+        TestRequest testSuiteDefinition =
+                new TestRequest( Arrays.asList( new File( "file1" ), new File( "file2" ) ),
+                        new File( "TestSOurce" ), new TestListResolver( "aUserRequestedTest#aMethodRequested" ) );
+        surefireReflector.setTestSuiteDefinition( foo, testSuiteDefinition );
+        assertTrue( isCalled( foo ) );
+    }
+
+    public void testProviderProperties()
+    {
+        SurefireReflector surefireReflector = getReflector();
+        Object foo = getFoo();
+
+        surefireReflector.setProviderProperties( foo, new HashMap<String, String>() );
+        assertTrue( isCalled( foo ) );
+    }
+
+    public void testReporterConfiguration()
+    {
+        SurefireReflector surefireReflector = getReflector();
+        Object foo = getFoo();
+
+        ReporterConfiguration reporterConfiguration = getReporterConfiguration();
+        surefireReflector.setReporterConfigurationAware( foo, reporterConfiguration );
+        assertTrue( isCalled( foo ) );
+    }
+
+    private ReporterConfiguration getReporterConfiguration()
+    {
+        return new ReporterConfiguration( new File( "CDE" ), true );
+    }
+
+    public void testTestClassLoaderAware()
+    {
+        SurefireReflector surefireReflector = getReflector();
+        Object foo = getFoo();
+
+        surefireReflector.setTestClassLoader( foo, getClass().getClassLoader() );
+        assertTrue( isCalled( foo ) );
+    }
+
+    public void testArtifactInfoAware()
+    {
+        SurefireReflector surefireReflector = getReflector();
+        Object foo = getFoo();
+
+        TestArtifactInfo testArtifactInfo = new TestArtifactInfo( "12.3", "test" );
+        surefireReflector.setTestArtifactInfo( foo, testArtifactInfo );
+        assertTrue( isCalled( foo ) );
+    }
+
+    private SurefireReflector getReflector()
+    {
+        return new SurefireReflector( this.getClass().getClassLoader() );
+    }
+
+    private Object getFoo()
+    { // Todo: Setup a different classloader so we can really test crossing
+        return new Foo();
+    }
+
+    private Boolean isCalled( Object foo )
+    {
+        final Method isCalled;
+        try
+        {
+            isCalled = foo.getClass().getMethod( "isCalled" );
+            return (Boolean) isCalled.invoke( foo );
+        }
+        catch ( ReflectiveOperationException e )
+        {
+            throw new RuntimeException( e );
+        }
+    }
 }
diff --git a/surefire-booter/pom.xml b/surefire-booter/pom.xml
index 74cd93c..1fe33e7 100644
--- a/surefire-booter/pom.xml
+++ b/surefire-booter/pom.xml
@@ -86,23 +86,39 @@
       <artifactId>powermock-api-mockito2</artifactId>
       <scope>test</scope>
     </dependency>
+    <dependency>
+      <groupId>org.jacoco</groupId>
+      <artifactId>org.jacoco.agent</artifactId>
+      <classifier>runtime</classifier>
+      <scope>test</scope>
+    </dependency>
   </dependencies>
 
   <build>
     <plugins>
       <plugin>
-        <artifactId>maven-dependency-plugin</artifactId>
+        <groupId>org.jacoco</groupId>
+        <artifactId>jacoco-maven-plugin</artifactId>
         <executions>
           <execution>
-            <id>build-test-classpath</id>
-            <phase>generate-sources</phase>
+            <id>jacoco-instrumentation</id>
             <goals>
-              <goal>build-classpath</goal>
+              <goal>instrument</goal>
+            </goals>
+          </execution>
+          <execution>
+            <id>restore-classes</id>
+            <goals>
+              <goal>restore-instrumented-classes</goal>
+            </goals>
+          </execution>
+          <execution>
+            <!--todo remove-->
+            <id>jacoco-report</id>
+            <phase>prepare-package</phase>
+            <goals>
+              <goal>report</goal>
             </goals>
-            <configuration>
-              <includeScope>test</includeScope>
-              <outputFile>target/test-classpath/cp.txt</outputFile>
-            </configuration>
           </execution>
         </executions>
       </plugin>
@@ -116,9 +132,13 @@
           </dependency>
         </dependencies>
         <configuration>
+          <argLine>${jvm.args.tests}</argLine>
           <includes>
             <include>**/JUnit4SuiteTest.java</include>
           </includes>
+          <systemPropertyVariables>
+            <jacoco-agent.destfile>${project.build.directory}/jacoco.exec</jacoco-agent.destfile>
+          </systemPropertyVariables>
         </configuration>
       </plugin>
       <plugin>
diff --git a/surefire-booter/src/test/java/org/apache/maven/surefire/booter/JUnit4SuiteTest.java b/surefire-booter/src/test/java/org/apache/maven/surefire/booter/JUnit4SuiteTest.java
index f073a8b..ff731c4 100644
--- a/surefire-booter/src/test/java/org/apache/maven/surefire/booter/JUnit4SuiteTest.java
+++ b/surefire-booter/src/test/java/org/apache/maven/surefire/booter/JUnit4SuiteTest.java
@@ -21,8 +21,8 @@ package org.apache.maven.surefire.booter;
 
 import junit.framework.JUnit4TestAdapter;
 import junit.framework.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Suite;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
 
 /**
  * Adapt the JUnit4 tests which use only annotations to the JUnit3 test suite.
@@ -30,19 +30,15 @@ import org.junit.runners.Suite;
  * @author Tibor Digana (tibor17)
  * @since 2.19
  */
-@Suite.SuiteClasses( {
-    ClasspathTest.class,
-    CommandReaderTest.class,
-    PropertiesWrapperTest.class,
-    SurefireReflectorTest.class,
-    PpidCheckerTest.class,
-    SystemUtilsTest.class
-} )
-@RunWith( Suite.class )
-public class JUnit4SuiteTest
+public class JUnit4SuiteTest extends TestCase
 {
     public static Test suite()
     {
-        return new JUnit4TestAdapter( JUnit4SuiteTest.class );
+        TestSuite suite = new TestSuite();
+        suite.addTest( new JUnit4TestAdapter( PpidCheckerTest.class ) );
+        suite.addTest( new JUnit4TestAdapter( SystemUtilsTest.class ) );
+        suite.addTestSuite( ClasspathTest.class );
+        suite.addTestSuite( PropertiesWrapperTest.class );
+        return suite;
     }
 }
diff --git a/surefire-booter/src/test/java/org/apache/maven/surefire/booter/SurefireReflectorTest.java b/surefire-booter/src/test/java/org/apache/maven/surefire/booter/SurefireReflectorTest.java
deleted file mode 100644
index 0f5188c..0000000
--- a/surefire-booter/src/test/java/org/apache/maven/surefire/booter/SurefireReflectorTest.java
+++ /dev/null
@@ -1,154 +0,0 @@
-package org.apache.maven.surefire.booter;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import java.io.File;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import org.apache.maven.surefire.report.ReporterConfiguration;
-import org.apache.maven.surefire.testset.DirectoryScannerParameters;
-import org.apache.maven.surefire.testset.RunOrderParameters;
-import org.apache.maven.surefire.testset.TestArtifactInfo;
-import org.apache.maven.surefire.testset.TestListResolver;
-import org.apache.maven.surefire.testset.TestRequest;
-import org.apache.maven.surefire.util.RunOrder;
-
-import junit.framework.TestCase;
-
-/**
- * @author Kristian Rosenvold
- */
-public class SurefireReflectorTest
-    extends TestCase
-{
-    public void testSetDirectoryScannerParameters()
-        throws Exception
-    {
-        SurefireReflector surefireReflector = getReflector();
-        Object foo = getFoo();
-
-        DirectoryScannerParameters directoryScannerParameters =
-            new DirectoryScannerParameters( new File( "ABC" ), new ArrayList<String>(), new ArrayList<String>(),
-                                            new ArrayList<String>(), false, "hourly" );
-        surefireReflector.setDirectoryScannerParameters( foo, directoryScannerParameters );
-        assertTrue( isCalled( foo ) );
-
-    }
-
-    public void testRunOrderParameters()
-        throws Exception
-    {
-        SurefireReflector surefireReflector = getReflector();
-        Object foo = getFoo();
-
-        RunOrderParameters runOrderParameters = new RunOrderParameters( RunOrder.DEFAULT, new File( "." ) );
-        surefireReflector.setRunOrderParameters( foo, runOrderParameters );
-        assertTrue( isCalled( foo ) );
-
-    }
-
-    public void testTestSuiteDefinition()
-        throws Exception
-    {
-        SurefireReflector surefireReflector = getReflector();
-        Object foo = getFoo();
-
-        TestRequest testSuiteDefinition =
-            new TestRequest( Arrays.asList( new File( "file1" ), new File( "file2" ) ),
-                             new File( "TestSOurce" ), new TestListResolver( "aUserRequestedTest#aMethodRequested" ) );
-        surefireReflector.setTestSuiteDefinition( foo, testSuiteDefinition );
-        assertTrue( isCalled( foo ) );
-    }
-
-    public void testProviderProperties()
-        throws Exception
-    {
-        SurefireReflector surefireReflector = getReflector();
-        Object foo = getFoo();
-
-        surefireReflector.setProviderProperties( foo, new HashMap<String, String>() );
-        assertTrue( isCalled( foo ) );
-    }
-
-    public void testReporterConfiguration()
-        throws Exception
-    {
-        SurefireReflector surefireReflector = getReflector();
-        Object foo = getFoo();
-
-        ReporterConfiguration reporterConfiguration = getReporterConfiguration();
-        surefireReflector.setReporterConfigurationAware( foo, reporterConfiguration );
-        assertTrue( isCalled( foo ) );
-    }
-
-    private ReporterConfiguration getReporterConfiguration()
-    {
-        return new ReporterConfiguration( new File( "CDE" ), true );
-    }
-
-    public void testTestClassLoaderAware()
-        throws Exception
-    {
-        SurefireReflector surefireReflector = getReflector();
-        Object foo = getFoo();
-
-        surefireReflector.setTestClassLoader( foo, getClass().getClassLoader() );
-        assertTrue( isCalled( foo ) );
-    }
-
-    public void testArtifactInfoAware()
-        throws Exception
-    {
-        SurefireReflector surefireReflector = getReflector();
-        Object foo = getFoo();
-
-        TestArtifactInfo testArtifactInfo = new TestArtifactInfo( "12.3", "test" );
-        surefireReflector.setTestArtifactInfo( foo, testArtifactInfo );
-        assertTrue( isCalled( foo ) );
-    }
-
-    private SurefireReflector getReflector()
-    {
-        return new SurefireReflector( this.getClass().getClassLoader() );
-    }
-
-    public Object getFoo()
-    { // Todo: Setup a different classloader so we can really test crossing
-        return new Foo();
-    }
-
-
-    private Boolean isCalled( Object foo )
-    {
-        final Method isCalled;
-        try
-        {
-            isCalled = foo.getClass().getMethod( "isCalled" );
-            return (Boolean) isCalled.invoke( foo );
-        }
-        catch ( ReflectiveOperationException e )
-        {
-            throw new RuntimeException( e );
-        }
-    }
-}
diff --git a/surefire-booter/src/test/java/org/apache/maven/surefire/booter/SystemUtilsTest.java b/surefire-booter/src/test/java/org/apache/maven/surefire/booter/SystemUtilsTest.java
index a957d06..438cb00 100644
--- a/surefire-booter/src/test/java/org/apache/maven/surefire/booter/SystemUtilsTest.java
+++ b/surefire-booter/src/test/java/org/apache/maven/surefire/booter/SystemUtilsTest.java
@@ -22,6 +22,7 @@ package org.apache.maven.surefire.booter;
 import org.junit.Test;
 import org.junit.experimental.runners.Enclosed;
 import org.junit.runner.RunWith;
+import org.powermock.core.classloader.annotations.PowerMockIgnore;
 import org.powermock.core.classloader.annotations.PrepareForTest;
 import org.powermock.modules.junit4.PowerMockRunner;
 
@@ -63,7 +64,8 @@ public class SystemUtilsTest
         public void shouldMatchJavaSpecVersion() throws Exception
         {
             BigDecimal actual = invokeMethod( SystemUtils.class, "getJavaSpecificationVersion" );
-            BigDecimal expected = new BigDecimal( System.getProperty( "java.specification.version" ) ).stripTrailingZeros();
+            BigDecimal expected =
+                    new BigDecimal( System.getProperty( "java.specification.version" ) ).stripTrailingZeros();
             assertThat( actual ).isEqualTo( expected );
             assertThat( SystemUtils.JAVA_SPECIFICATION_VERSION ).isEqualTo( expected );
         }
@@ -295,6 +297,7 @@ public class SystemUtilsTest
 
     @RunWith( PowerMockRunner.class )
     @PrepareForTest( SystemUtils.class )
+    @PowerMockIgnore( { "org.jacoco.agent.rt.*", "com.vladium.emma.rt.*" } )
     public static class MockTest
     {
 
diff --git a/surefire-extensions-api/pom.xml b/surefire-extensions-api/pom.xml
index 6daae03..db0aafa 100644
--- a/surefire-extensions-api/pom.xml
+++ b/surefire-extensions-api/pom.xml
@@ -44,6 +44,62 @@
             <artifactId>plexus-component-annotations</artifactId>
             <scope>provided</scope>
         </dependency>
+        <dependency>
+            <groupId>org.jacoco</groupId>
+            <artifactId>org.jacoco.agent</artifactId>
+            <classifier>runtime</classifier>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.jacoco</groupId>
+                <artifactId>jacoco-maven-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>jacoco-instrumentation</id>
+                        <!--
+                        phase: the order of the plugins matters and maven-plugin-plugin must be before jacoco plugin
+                        -->
+                        <goals>
+                            <goal>instrument</goal>
+                        </goals>
+                    </execution>
+                    <execution>
+                        <id>restore-classes</id>
+                        <goals>
+                            <goal>restore-instrumented-classes</goal>
+                        </goals>
+                    </execution>
+                    <execution>
+                        <!--todo remove-->
+                        <id>jacoco-report</id>
+                        <phase>prepare-package</phase>
+                        <goals>
+                            <goal>report</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <artifactId>maven-surefire-plugin</artifactId>
+                <dependencies>
+                    <dependency>
+                        <groupId>org.apache.maven.surefire</groupId>
+                        <artifactId>surefire-shadefire</artifactId>
+                        <version>3.0.0-M3</version> <!-- ${shadedVersion}, but resolved due to https://issues.apache.org/jira/browse/MRELEASE-799 -->
+                    </dependency>
+                </dependencies>
+                <configuration>
+                    <argLine>${jvm.args.tests}</argLine>
+                    <systemPropertyVariables>
+                        <jacoco-agent.destfile>${project.build.directory}/jacoco.exec</jacoco-agent.destfile>
+                    </systemPropertyVariables>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
 </project>
\ No newline at end of file
diff --git a/surefire-grouper/pom.xml b/surefire-grouper/pom.xml
index 9aa676c..d3ae750 100644
--- a/surefire-grouper/pom.xml
+++ b/surefire-grouper/pom.xml
@@ -52,7 +52,33 @@
         </executions>
       </plugin>
       <plugin>
+        <groupId>org.jacoco</groupId>
+        <artifactId>jacoco-maven-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>jacoco-agent</id>
+            <goals>
+              <goal>prepare-agent</goal>
+            </goals>
+          </execution>
+          <execution>
+            <!--todo remove-->
+            <id>jacoco-report</id>
+            <phase>prepare-package</phase>
+            <goals>
+              <goal>report</goal>
+            </goals>
+          </execution>
+        </executions>
+        <configuration>
+          <propertyName>jacoco.agent</propertyName>
+        </configuration>
+      </plugin>
+      <plugin>
         <artifactId>maven-surefire-plugin</artifactId>
+        <configuration>
+          <argLine>${jvm.args.tests} ${jacoco.agent}</argLine>
+        </configuration>
         <dependencies>
           <dependency>
             <groupId>org.apache.maven.surefire</groupId>
diff --git a/surefire-logger-api/pom.xml b/surefire-logger-api/pom.xml
index 4a56f3a..429c754 100644
--- a/surefire-logger-api/pom.xml
+++ b/surefire-logger-api/pom.xml
@@ -49,4 +49,56 @@
         </developer>
     </developers>
 
+    <dependencies>
+        <dependency>
+            <groupId>org.mockito</groupId>
+            <artifactId>mockito-core</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.jacoco</groupId>
+                <artifactId>jacoco-maven-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>jacoco-agent</id>
+                        <goals>
+                            <goal>prepare-agent</goal>
+                        </goals>
+                    </execution>
+                    <execution>
+                        <!--todo remove-->
+                        <id>jacoco-report</id>
+                        <phase>prepare-package</phase>
+                        <goals>
+                            <goal>report</goal>
+                        </goals>
+                    </execution>
+                </executions>
+                <configuration>
+                    <propertyName>jacoco.agent</propertyName>
+                </configuration>
+            </plugin>
+            <plugin>
+                <artifactId>maven-surefire-plugin</artifactId>
+                <configuration>
+                    <argLine>${jvm.args.tests} ${jacoco.agent}</argLine>
+                    <includes>
+                        <include>**/JUnit4SuiteTest.java</include>
+                    </includes>
+                </configuration>
+                <dependencies>
+                    <dependency>
+                        <groupId>org.apache.maven.surefire</groupId>
+                        <artifactId>surefire-shadefire</artifactId>
+                        <version>3.0.0-M3</version> <!-- ${shadedVersion}, but resolved due to https://issues.apache.org/jira/browse/MRELEASE-799 -->
+                    </dependency>
+                </dependencies>
+            </plugin>
+        </plugins>
+    </build>
+
 </project>
diff --git a/surefire-logger-api/src/main/java/org/apache/maven/plugin/surefire/log/api/ConsoleLoggerDecorator.java b/surefire-logger-api/src/main/java/org/apache/maven/plugin/surefire/log/api/ConsoleLoggerDecorator.java
index 02105fa..5938fc1 100644
--- a/surefire-logger-api/src/main/java/org/apache/maven/plugin/surefire/log/api/ConsoleLoggerDecorator.java
+++ b/surefire-logger-api/src/main/java/org/apache/maven/plugin/surefire/log/api/ConsoleLoggerDecorator.java
@@ -1 +1 @@
-package org.apache.maven.plugin.surefire.log.api;

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

/**
 * Decorator around {@link ConsoleLogger}.
 * This class is loaded in the isolated ClassLoader and the child logger in the in-plugi
 n ClassLoader.
 *
 * @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
 * @since 2.20
 */
public final class ConsoleLoggerDecorator
        implements ConsoleLogger
{
    private final Object logger;

    public ConsoleLoggerDecorator( Object logger )
    {
        if ( logger == null )
        {
            throw new NullPointerException( "logger argument is null in " + ConsoleLoggerDecorator.class );
        }
        this.logger = logger;
    }

    @Override
    public boolean isDebugEnabled()
    {
        try
        {
            return (Boolean) logger.getClass()
                    .getMethod( "isDebugEnabled" )
                    .invoke( logger );
        }
        catch ( Exception e )
        {
            throw new IllegalStateException( e.getLocalizedMessage(), e );
        }
    }

    @Override
    public void debug( String message )
    {
        try
        {
            logger.getClass()
                    .getMethod( "debug", String.cl
 ass )
                    .invoke( logger, message );
        }
        catch ( Exception e )
        {
            throw new IllegalStateException( e.getLocalizedMessage(), e );
        }
    }

    @Override
    public boolean isInfoEnabled()
    {
        try
        {
            return (Boolean) logger.getClass()
                    .getMethod( "isInfoEnabled" )
                    .invoke( logger );
        }
        catch ( Exception e )
        {
            throw new IllegalStateException( e.getLocalizedMessage(), e );
        }
    }

    @Override
    public void info( String message )
    {
        try
        {
            logger.getClass()
                    .getMethod( "info", String.class )
                    .invoke( logger, message );
        }
        catch ( Exception e )
        {
            throw new IllegalStateException( e.getLocalizedMessage(), e );
        }
    }

    @Override
    public boolean isWarnEnabled()
    {
        try
        {
            r
 eturn (Boolean) logger.getClass()
                    .getMethod( "isWarnEnabled" )
                    .invoke( logger );
        }
        catch ( Exception e )
        {
            throw new IllegalStateException( e.getLocalizedMessage(), e );
        }
    }

    @Override
    public void warning( String message )
    {
        try
        {
            logger.getClass()
                    .getMethod( "warning", String.class )
                    .invoke( logger, message );
        }
        catch ( Exception e )
        {
            throw new IllegalStateException( e.getLocalizedMessage(), e );
        }
    }

    @Override
    public boolean isErrorEnabled()
    {
        try
        {
            return (Boolean) logger.getClass()
                    .getMethod( "isErrorEnabled" )
                    .invoke( logger );
        }
        catch ( Exception e )
        {
            throw new IllegalStateException( e.getLocalizedMessage(), e );
        }
    }

    @Override
 
    public void error( String message )
    {
        try
        {
            logger.getClass()
                    .getMethod( "error", String.class )
                    .invoke( logger, message );
        }
        catch ( Exception e )
        {
            throw new IllegalStateException( e.getLocalizedMessage(), e );
        }
    }

    @Override
    public void error( String message, Throwable t )
    {
        try
        {
            logger.getClass()
                    .getMethod( "error", String.class, Throwable.class )
                    .invoke( logger, message, t );
        }
        catch ( Exception e )
        {
            throw new IllegalStateException( e.getLocalizedMessage(), e );
        }
    }

    @Override
    public void error( Throwable t )
    {
        try
        {
            logger.getClass()
                    .getMethod( "error", Throwable.class )
                    .invoke( logger, t );
        }
        catch ( Exception e )
        {
 
            throw new IllegalStateException( e.getLocalizedMessage(), e );
        }
    }
}
\ No newline at end of file
+package org.apache.maven.plugin.surefire.log.api;

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

/**
 * Decorator around {@link ConsoleLogger}.
 * This class is loaded in the isolated ClassLoader and the child logger in the in-plugi
 n ClassLoader.
 *
 * @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
 * @since 2.20
 */
public final class ConsoleLoggerDecorator
        implements ConsoleLogger
{
    private final Object logger;

    public ConsoleLoggerDecorator( Object logger )
    {
        if ( logger == null )
        {
            throw new NullPointerException( "logger argument is null in " + ConsoleLoggerDecorator.class );
        }
        this.logger = logger;
    }

    @Override
    public boolean isDebugEnabled()
    {
        return invokeReturnedBoolean( "isDebugEnabled" );
    }

    @Override
    public void debug( String message )
    {
        invokeWithMessage( message, "debug" );
    }

    @Override
    public boolean isInfoEnabled()
    {
        return invokeReturnedBoolean( "isInfoEnabled" );
    }

    @Override
    public void info( String message )
    {
        invokeWithMessage( message, "info" );
    }

    @Override
    public boolean isWarnEnabled()
    
 {
        return invokeReturnedBoolean( "isWarnEnabled" );
    }

    @Override
    public void warning( String message )
    {
        invokeWithMessage( message, "warning" );
    }

    @Override
    public boolean isErrorEnabled()
    {
        return invokeReturnedBoolean( "isErrorEnabled" );
    }

    @Override
    public void error( String message )
    {
        invokeWithMessage( message, "error" );
    }

    @Override
    public void error( String message, Throwable t )
    {
        try
        {
            logger.getClass()
                    .getMethod( "error", String.class, Throwable.class )
                    .invoke( logger, message, t );
        }
        catch ( Exception e )
        {
            throw new IllegalStateException( e.getLocalizedMessage(), e );
        }
    }

    @Override
    public void error( Throwable t )
    {
        try
        {
            logger.getClass()
                    .getMethod( "error", Throwable.class )
                   
  .invoke( logger, t );
        }
        catch ( Exception e )
        {
            throw new IllegalStateException( e.getLocalizedMessage(), e );
        }
    }

    private boolean invokeReturnedBoolean( String isErrorEnabled )
    {
        try
        {
            return (Boolean) logger.getClass()
                    .getMethod( isErrorEnabled )
                    .invoke( logger );
        }
        catch ( Exception e )
        {
            throw new IllegalStateException( e.getLocalizedMessage(), e );
        }
    }

    private void invokeWithMessage( String message, String error )
    {
        try
        {
            logger.getClass()
                    .getMethod( error, String.class )
                    .invoke( logger, message );
        }
        catch ( Exception e )
        {
            throw new IllegalStateException( e.getLocalizedMessage(), e );
        }
    }
}
\ No newline at end of file
diff --git a/surefire-logger-api/src/test/java/org/apache/maven/plugin/surefire/log/api/ConsoleLoggerUtilsTest.java b/surefire-logger-api/src/test/java/org/apache/maven/plugin/surefire/log/api/ConsoleLoggerUtilsTest.java
new file mode 100644
index 0000000..902a17e
--- /dev/null
+++ b/surefire-logger-api/src/test/java/org/apache/maven/plugin/surefire/log/api/ConsoleLoggerUtilsTest.java
@@ -0,0 +1,64 @@
+package org.apache.maven.plugin.surefire.log.api;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import org.junit.Test;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import static org.fest.assertions.Assertions.assertThat;
+
+/**
+ * Tests for {@link ConsoleLoggerUtils}.
+ */
+public class ConsoleLoggerUtilsTest
+{
+    @Test
+    public void shouldPrintStacktraceAsString()
+    {
+        Exception e = new IllegalArgumentException( "wrong param" );
+        String msg = ConsoleLoggerUtils.toString( e );
+
+        StringWriter text = new StringWriter();
+        PrintWriter writer = new PrintWriter( text );
+        e.printStackTrace( writer );
+        String s = text.toString();
+
+        assertThat( msg )
+                .isEqualTo( s );
+    }
+
+    @Test
+    public void shouldPrintStacktracWithMessageAsString()
+    {
+        Exception e = new IllegalArgumentException( "wrong param" );
+        String msg = ConsoleLoggerUtils.toString( "issue", e );
+
+        StringWriter text = new StringWriter();
+        PrintWriter writer = new PrintWriter( text );
+        writer.println( "issue" );
+        e.printStackTrace( writer );
+        String s = text.toString();
+
+        assertThat( msg )
+                .isEqualTo( s );
+    }
+}
diff --git a/surefire-report-parser/src/test/java/org/apache/maven/plugins/surefire/report/JUnit4SuiteTest.java b/surefire-logger-api/src/test/java/org/apache/maven/plugin/surefire/log/api/JUnit4SuiteTest.java
similarity index 81%
copy from surefire-report-parser/src/test/java/org/apache/maven/plugins/surefire/report/JUnit4SuiteTest.java
copy to surefire-logger-api/src/test/java/org/apache/maven/plugin/surefire/log/api/JUnit4SuiteTest.java
index 142ca9d..69665a3 100644
--- a/surefire-report-parser/src/test/java/org/apache/maven/plugins/surefire/report/JUnit4SuiteTest.java
+++ b/surefire-logger-api/src/test/java/org/apache/maven/plugin/surefire/log/api/JUnit4SuiteTest.java
@@ -1,4 +1,4 @@
-package org.apache.maven.plugins.surefire.report;
+package org.apache.maven.plugin.surefire.log.api;
 
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
@@ -21,23 +21,20 @@ package org.apache.maven.plugins.surefire.report;
 
 import junit.framework.JUnit4TestAdapter;
 import junit.framework.Test;
+import junit.framework.TestCase;
 import org.junit.runner.RunWith;
 import org.junit.runners.Suite;
+import org.junit.runners.Suite.SuiteClasses;
 
 /**
  * Adapt the JUnit4 tests which use only annotations to the JUnit3 test suite.
  *
  * @author Tibor Digana (tibor17)
- * @since 2.21.0
+ * @since 3.0.0-M4
  */
-@Suite.SuiteClasses( {
-        ReportTestCaseTest.class,
-        ReportTestSuiteTest.class,
-        SurefireReportParserTest.class,
-        TestSuiteXmlParserTest.class
-} )
+@SuiteClasses( { ConsoleLoggerUtilsTest.class, LevelTest.class, LoggersTest.class } )
 @RunWith( Suite.class )
-public class JUnit4SuiteTest
+public class JUnit4SuiteTest extends TestCase
 {
     public static Test suite()
     {
diff --git a/surefire-logger-api/src/test/java/org/apache/maven/plugin/surefire/log/api/LevelTest.java b/surefire-logger-api/src/test/java/org/apache/maven/plugin/surefire/log/api/LevelTest.java
new file mode 100644
index 0000000..0f48880
--- /dev/null
+++ b/surefire-logger-api/src/test/java/org/apache/maven/plugin/surefire/log/api/LevelTest.java
@@ -0,0 +1,73 @@
+package org.apache.maven.plugin.surefire.log.api;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import org.junit.Test;
+
+import static org.apache.maven.plugin.surefire.log.api.Level.resolveLevel;
+import static org.fest.assertions.Assertions.assertThat;
+
+/**
+ * Tests for {@link Level}.
+ */
+public class LevelTest
+{
+    @Test
+    public void shouldHaveSuccess()
+    {
+        Level level = resolveLevel( true, false, false, false, false );
+        assertThat( level ).isEqualTo( Level.SUCCESS );
+    }
+
+    @Test
+    public void shouldNotHaveSuccess()
+    {
+        Level level = resolveLevel( false, false, false, false, false );
+        assertThat( level ).isEqualTo( Level.NO_COLOR );
+    }
+
+    @Test
+    public void shouldBeFailure()
+    {
+        Level level = resolveLevel( false, true, false, false, false );
+        assertThat( level ).isEqualTo( Level.FAILURE );
+    }
+
+    @Test
+    public void shouldBeError()
+    {
+        Level level = resolveLevel( false, false, true, false, false );
+        assertThat( level ).isEqualTo( Level.FAILURE );
+    }
+
+    @Test
+    public void shouldBeSkipped()
+    {
+        Level level = resolveLevel( false, false, false, true, false );
+        assertThat( level ).isEqualTo( Level.UNSTABLE );
+    }
+
+    @Test
+    public void shouldBeFlake()
+    {
+        Level level = resolveLevel( false, false, false, false, true );
+        assertThat( level ).isEqualTo( Level.UNSTABLE );
+    }
+}
diff --git a/surefire-logger-api/src/test/java/org/apache/maven/plugin/surefire/log/api/LoggersTest.java b/surefire-logger-api/src/test/java/org/apache/maven/plugin/surefire/log/api/LoggersTest.java
new file mode 100644
index 0000000..7de9148
--- /dev/null
+++ b/surefire-logger-api/src/test/java/org/apache/maven/plugin/surefire/log/api/LoggersTest.java
@@ -0,0 +1,139 @@
+package org.apache.maven.plugin.surefire.log.api;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mockito;
+import org.mockito.internal.matchers.CapturesArguments;
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+
+import static org.fest.assertions.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+/**
+ * Tests for {@link ConsoleLoggerDecorator}, {@link NullConsoleLogger} and {@link PrintStreamLogger}.
+ */
+public class LoggersTest
+{
+    @Test
+    public void testPrintStreamLogger()
+    {
+        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+        PrintStream printStream = new PrintStream( outputStream );
+        PrintStreamLogger logger = new PrintStreamLogger( printStream );
+
+
+        assertThat( logger.isErrorEnabled() ).isTrue();
+        assertThat( logger.isWarnEnabled() ).isTrue();
+        assertThat( logger.isInfoEnabled() ).isTrue();
+        assertThat( logger.isDebugEnabled() ).isTrue();
+
+        logger.error( "error" );
+        logger.debug( "debug" );
+        logger.info( "info" );
+        logger.warning( "warning" );
+
+        String line = System.lineSeparator();
+        assertThat( outputStream.toString() )
+                .isEqualTo( "error" + line + "debug" + line + "info" + line + "warning" + line );
+
+        Exception e = new Exception( "exception" );
+        outputStream.reset();
+        logger.error( e );
+        assertThat( outputStream.toString() )
+                .contains( "java.lang.Exception: exception" )
+                .contains( "at " + getClass().getName() + ".testPrintStreamLogger(LoggersTest.java:63)" );
+    }
+
+    @Test( expected = NullPointerException.class )
+    public void shouldThrowNPE()
+    {
+        new ConsoleLoggerDecorator( null );
+    }
+
+    @Test
+    public void testDecorator()
+    {
+        ConsoleLogger logger = mock( ConsoleLogger.class );
+        ConsoleLoggerDecorator decorator = new ConsoleLoggerDecorator( logger );
+
+        assertThat( decorator.isDebugEnabled() ).isFalse();
+        when( logger.isDebugEnabled() ).thenReturn( true );
+        assertThat( decorator.isDebugEnabled() ).isTrue();
+
+        assertThat( decorator.isInfoEnabled() ).isFalse();
+        when( logger.isInfoEnabled() ).thenReturn( true );
+        assertThat( decorator.isInfoEnabled() ).isTrue();
+
+        assertThat( decorator.isWarnEnabled() ).isFalse();
+        when( logger.isWarnEnabled() ).thenReturn( true );
+        assertThat( decorator.isWarnEnabled() ).isTrue();
+
+        assertThat( decorator.isErrorEnabled() ).isFalse();
+        when( logger.isErrorEnabled() ).thenReturn( true );
+        assertThat( decorator.isErrorEnabled() ).isTrue();
+
+        ArgumentCaptor<String> argumentMsg = ArgumentCaptor.forClass( String.class );
+        decorator.debug( "debug" );
+        verify( logger, times( 1 ) ).debug( argumentMsg.capture() );
+        assertThat( argumentMsg.getAllValues() ).hasSize( 1 );
+        assertThat( argumentMsg.getAllValues().get( 0 ) ).isEqualTo( "debug" );
+
+        argumentMsg = ArgumentCaptor.forClass( String.class );
+        decorator.info( "info" );
+        verify( logger, times( 1 ) ).info( argumentMsg.capture() );
+        assertThat( argumentMsg.getAllValues() ).hasSize( 1 );
+        assertThat( argumentMsg.getAllValues().get( 0 ) ).isEqualTo( "info" );
+
+        argumentMsg = ArgumentCaptor.forClass( String.class );
+        decorator.warning( "warning" );
+        verify( logger, times( 1 ) ).warning( argumentMsg.capture() );
+        assertThat( argumentMsg.getAllValues() ).hasSize( 1 );
+        assertThat( argumentMsg.getAllValues().get( 0 ) ).isEqualTo( "warning" );
+
+        argumentMsg = ArgumentCaptor.forClass( String.class );
+        decorator.error( "error" );
+        verify( logger, times( 1 ) ).error( argumentMsg.capture() );
+        assertThat( argumentMsg.getAllValues() ).hasSize( 1 );
+        assertThat( argumentMsg.getAllValues().get( 0 ) ).isEqualTo( "error" );
+
+        ArgumentCaptor<Throwable> argumentThrowable = ArgumentCaptor.forClass( Throwable.class );
+        argumentMsg = ArgumentCaptor.forClass( String.class );
+        Exception e = new Exception();
+        decorator.error( "error", e );
+        verify( logger, times( 1 ) ).error( argumentMsg.capture(), argumentThrowable.capture() );
+        assertThat( argumentMsg.getAllValues() ).hasSize( 1 );
+        assertThat( argumentMsg.getAllValues().get( 0 ) ).isEqualTo( "error" );
+        assertThat( argumentThrowable.getAllValues() ).hasSize( 1 );
+        assertThat( argumentThrowable.getAllValues().get( 0 ) ).isSameAs( e );
+
+        argumentThrowable = ArgumentCaptor.forClass( Throwable.class );
+        decorator.error( e );
+        verify( logger, times( 1 ) ).error( argumentThrowable.capture() );
+        assertThat( argumentThrowable.getAllValues() ).hasSize( 1 );
+        assertThat( argumentThrowable.getAllValues().get( 0 ) ).isSameAs( e );
+    }
+}
diff --git a/surefire-providers/common-java5/pom.xml b/surefire-providers/common-java5/pom.xml
index ba44a98..7ecf6af 100644
--- a/surefire-providers/common-java5/pom.xml
+++ b/surefire-providers/common-java5/pom.xml
@@ -41,6 +41,29 @@
   <build>
     <plugins>
       <plugin>
+        <groupId>org.jacoco</groupId>
+        <artifactId>jacoco-maven-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>jacoco-agent</id>
+            <goals>
+              <goal>prepare-agent</goal>
+            </goals>
+          </execution>
+          <execution>
+            <!--todo remove-->
+            <id>jacoco-report</id>
+            <phase>prepare-package</phase>
+            <goals>
+              <goal>report</goal>
+            </goals>
+          </execution>
+        </executions>
+        <configuration>
+          <propertyName>jacoco.agent</propertyName>
+        </configuration>
+      </plugin>
+      <plugin>
         <artifactId>maven-shade-plugin</artifactId>
         <executions>
           <execution>
@@ -68,10 +91,15 @@
       <plugin>
         <artifactId>maven-surefire-plugin</artifactId>
         <configuration>
-          <excludes>
-            <exclude>**/fixture/**</exclude>
-          </excludes>
+          <argLine>${jvm.args.tests} ${jacoco.agent}</argLine>
         </configuration>
+        <dependencies>
+          <dependency>
+            <groupId>org.apache.maven.surefire</groupId>
+            <artifactId>surefire-shadefire</artifactId>
+            <version>3.0.0-M3</version> <!-- ${shadedVersion}, but resolved due to https://issues.apache.org/jira/browse/MRELEASE-799 -->
+          </dependency>
+        </dependencies>
       </plugin>
     </plugins>
   </build>
diff --git a/surefire-providers/common-junit3/pom.xml b/surefire-providers/common-junit3/pom.xml
index 2089eec..9d314ba 100644
--- a/surefire-providers/common-junit3/pom.xml
+++ b/surefire-providers/common-junit3/pom.xml
@@ -40,4 +40,45 @@
     </dependency>
   </dependencies>
 
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.jacoco</groupId>
+        <artifactId>jacoco-maven-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>jacoco-agent</id>
+            <goals>
+              <goal>prepare-agent</goal>
+            </goals>
+          </execution>
+          <execution>
+            <!--todo remove-->
+            <id>jacoco-report</id>
+            <phase>prepare-package</phase>
+            <goals>
+              <goal>report</goal>
+            </goals>
+          </execution>
+        </executions>
+        <configuration>
+          <propertyName>jacoco.agent</propertyName>
+        </configuration>
+      </plugin>
+      <plugin>
+        <artifactId>maven-surefire-plugin</artifactId>
+        <configuration>
+          <argLine>${jvm.args.tests} ${jacoco.agent}</argLine>
+        </configuration>
+        <dependencies>
+          <dependency>
+            <groupId>org.apache.maven.surefire</groupId>
+            <artifactId>surefire-shadefire</artifactId>
+            <version>3.0.0-M3</version> <!-- ${shadedVersion}, but resolved due to https://issues.apache.org/jira/browse/MRELEASE-799 -->
+          </dependency>
+        </dependencies>
+      </plugin>
+    </plugins>
+  </build>
+
 </project>
diff --git a/surefire-providers/common-junit4/pom.xml b/surefire-providers/common-junit4/pom.xml
index 0af781c..0bcd734 100644
--- a/surefire-providers/common-junit4/pom.xml
+++ b/surefire-providers/common-junit4/pom.xml
@@ -49,4 +49,45 @@
       <version>${project.version}</version>
     </dependency>
   </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.jacoco</groupId>
+        <artifactId>jacoco-maven-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>jacoco-agent</id>
+            <goals>
+              <goal>prepare-agent</goal>
+            </goals>
+          </execution>
+          <execution>
+            <!--todo remove-->
+            <id>jacoco-report</id>
+            <phase>prepare-package</phase>
+            <goals>
+              <goal>report</goal>
+            </goals>
+          </execution>
+        </executions>
+        <configuration>
+          <propertyName>jacoco.agent</propertyName>
+        </configuration>
+      </plugin>
+      <plugin>
+        <artifactId>maven-surefire-plugin</artifactId>
+        <configuration>
+          <argLine>${jvm.args.tests} ${jacoco.agent}</argLine>
+        </configuration>
+        <dependencies>
+          <dependency>
+            <groupId>org.apache.maven.surefire</groupId>
+            <artifactId>surefire-shadefire</artifactId>
+            <version>3.0.0-M3</version> <!-- ${shadedVersion}, but resolved due to https://issues.apache.org/jira/browse/MRELEASE-799 -->
+          </dependency>
+        </dependencies>
+      </plugin>
+    </plugins>
+  </build>
 </project>
diff --git a/surefire-providers/common-junit48/pom.xml b/surefire-providers/common-junit48/pom.xml
index ddfdf75..569a1a5 100644
--- a/surefire-providers/common-junit48/pom.xml
+++ b/surefire-providers/common-junit48/pom.xml
@@ -58,12 +58,43 @@
   <build>
     <plugins>
       <plugin>
+        <groupId>org.jacoco</groupId>
+        <artifactId>jacoco-maven-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>jacoco-agent</id>
+            <goals>
+              <goal>prepare-agent</goal>
+            </goals>
+          </execution>
+          <execution>
+            <!--todo remove-->
+            <id>jacoco-report</id>
+            <phase>prepare-package</phase>
+            <goals>
+              <goal>report</goal>
+            </goals>
+          </execution>
+        </executions>
+        <configuration>
+          <propertyName>jacoco.agent</propertyName>
+        </configuration>
+      </plugin>
+      <plugin>
         <artifactId>maven-surefire-plugin</artifactId>
         <configuration>
+          <argLine>${jvm.args.tests} ${jacoco.agent}</argLine>
           <includes>
             <include>**/JUnit4SuiteTest.java</include>
           </includes>
         </configuration>
+        <dependencies>
+          <dependency>
+            <groupId>org.apache.maven.surefire</groupId>
+            <artifactId>surefire-shadefire</artifactId>
+            <version>3.0.0-M3</version> <!-- ${shadedVersion}, but resolved due to https://issues.apache.org/jira/browse/MRELEASE-799 -->
+          </dependency>
+        </dependencies>
       </plugin>
     </plugins>
   </build>
diff --git a/surefire-providers/common-junit48/src/test/java/org/apache/maven/surefire/common/junit48/JUnit4SuiteTest.java b/surefire-providers/common-junit48/src/test/java/org/apache/maven/surefire/common/junit48/JUnit4SuiteTest.java
index 547c381..191e1e8 100644
--- a/surefire-providers/common-junit48/src/test/java/org/apache/maven/surefire/common/junit48/JUnit4SuiteTest.java
+++ b/surefire-providers/common-junit48/src/test/java/org/apache/maven/surefire/common/junit48/JUnit4SuiteTest.java
@@ -21,8 +21,8 @@ package org.apache.maven.surefire.common.junit48;
 
 import junit.framework.JUnit4TestAdapter;
 import junit.framework.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Suite;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
 
 /**
  * Adapt the JUnit4 tests which use only annotations to the JUnit3 test suite.
@@ -30,16 +30,14 @@ import org.junit.runners.Suite;
  * @author Tibor Digana (tibor17)
  * @since 2.19
  */
-@Suite.SuiteClasses( {
-    FilterFactoryTest.class,
-    JUnit48ReflectorTest.class,
-    JUnit48TestCheckerTest.class
-} )
-@RunWith( Suite.class )
-public class JUnit4SuiteTest
+public class JUnit4SuiteTest extends TestCase
 {
     public static Test suite()
     {
-        return new JUnit4TestAdapter( JUnit4SuiteTest.class );
+        TestSuite suite = new TestSuite();
+        suite.addTestSuite( JUnit48ReflectorTest.class );
+        suite.addTest( new JUnit4TestAdapter( JUnit48TestCheckerTest.class ) );
+        suite.addTest( new JUnit4TestAdapter( FilterFactoryTest.class ) );
+        return suite;
     }
 }
diff --git a/surefire-providers/surefire-junit-platform/pom.xml b/surefire-providers/surefire-junit-platform/pom.xml
index eaaaeef..bdf5c9a 100644
--- a/surefire-providers/surefire-junit-platform/pom.xml
+++ b/surefire-providers/surefire-junit-platform/pom.xml
@@ -115,6 +115,29 @@
     <build>
         <plugins>
             <plugin>
+                <groupId>org.jacoco</groupId>
+                <artifactId>jacoco-maven-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>jacoco-agent</id>
+                        <goals>
+                            <goal>prepare-agent</goal>
+                        </goals>
+                    </execution>
+                    <execution>
+                        <!--todo remove-->
+                        <id>jacoco-report</id>
+                        <phase>prepare-package</phase>
+                        <goals>
+                            <goal>report</goal>
+                        </goals>
+                    </execution>
+                </executions>
+                <configuration>
+                    <propertyName>jacoco.agent</propertyName>
+                </configuration>
+            </plugin>
+            <plugin>
                 <groupId>org.codehaus.mojo</groupId>
                 <artifactId>animal-sniffer-maven-plugin</artifactId>
                 <executions>
@@ -143,6 +166,7 @@
                 <artifactId>maven-surefire-plugin</artifactId>
                 <version>3.0.0-M3</version> <!-- ${shadedVersion}, but resolved due to https://issues.apache.org/jira/browse/MRELEASE-799 -->
                 <configuration>
+                    <argLine>${jvm.args.tests} ${jacoco.agent}</argLine>
                     <jvm>${java.home}/bin/java</jvm>
                     <redirectTestOutputToFile>true</redirectTestOutputToFile>
                     <includes>
diff --git a/surefire-providers/surefire-junit-platform/src/test/java/org/apache/maven/surefire/junitplatform/JUnit47SuiteTest.java b/surefire-providers/surefire-junit-platform/src/test/java/org/apache/maven/surefire/junitplatform/JUnit47SuiteTest.java
index d0d4af9..7db25c9 100644
--- a/surefire-providers/surefire-junit-platform/src/test/java/org/apache/maven/surefire/junitplatform/JUnit47SuiteTest.java
+++ b/surefire-providers/surefire-junit-platform/src/test/java/org/apache/maven/surefire/junitplatform/JUnit47SuiteTest.java
@@ -21,26 +21,23 @@ package org.apache.maven.surefire.junitplatform;
 
 import junit.framework.JUnit4TestAdapter;
 import junit.framework.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Suite;
-import org.junit.runners.Suite.SuiteClasses;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
 
 /**
  * Adapt the JUnit4 tests which use only annotations to the JUnit3 test suite.
  *
  * @since 3.0.0-M4
  */
-@SuiteClasses( {
-        JUnitPlatformProviderTest.class,
-        RunListenerAdapterTest.class,
-        TestMethodFilterTest.class,
-        TestPlanScannerFilterTest.class
-} )
-@RunWith( Suite.class )
-public class JUnit47SuiteTest
+public class JUnit47SuiteTest extends TestCase
 {
     public static Test suite()
     {
-        return new JUnit4TestAdapter( JUnit47SuiteTest.class );
+        TestSuite suite = new TestSuite();
+        suite.addTest( new JUnit4TestAdapter( JUnitPlatformProviderTest.class ) );
+        suite.addTest( new JUnit4TestAdapter( RunListenerAdapterTest.class ) );
+        suite.addTest( new JUnit4TestAdapter( TestMethodFilterTest.class ) );
+        suite.addTest( new JUnit4TestAdapter( TestPlanScannerFilterTest.class ) );
+        return suite;
     }
 }
diff --git a/surefire-providers/surefire-junit3/pom.xml b/surefire-providers/surefire-junit3/pom.xml
index 44d608e..a163a7f 100644
--- a/surefire-providers/surefire-junit3/pom.xml
+++ b/surefire-providers/surefire-junit3/pom.xml
@@ -44,4 +44,45 @@
       <version>${project.version}</version>
     </dependency>
   </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.jacoco</groupId>
+        <artifactId>jacoco-maven-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>jacoco-agent</id>
+            <goals>
+              <goal>prepare-agent</goal>
+            </goals>
+          </execution>
+          <execution>
+            <!--todo remove-->
+            <id>jacoco-report</id>
+            <phase>prepare-package</phase>
+            <goals>
+              <goal>report</goal>
+            </goals>
+          </execution>
+        </executions>
+        <configuration>
+          <propertyName>jacoco.agent</propertyName>
+        </configuration>
+      </plugin>
+      <plugin>
+        <artifactId>maven-surefire-plugin</artifactId>
+        <configuration>
+          <argLine>${jvm.args.tests} ${jacoco.agent}</argLine>
+        </configuration>
+        <dependencies>
+          <dependency>
+            <groupId>org.apache.maven.surefire</groupId>
+            <artifactId>surefire-shadefire</artifactId>
+            <version>3.0.0-M3</version> <!-- ${shadedVersion}, but resolved due to https://issues.apache.org/jira/browse/MRELEASE-799 -->
+          </dependency>
+        </dependencies>
+      </plugin>
+    </plugins>
+  </build>
 </project>
diff --git a/surefire-providers/surefire-junit4/pom.xml b/surefire-providers/surefire-junit4/pom.xml
index d3816ad..693185a 100644
--- a/surefire-providers/surefire-junit4/pom.xml
+++ b/surefire-providers/surefire-junit4/pom.xml
@@ -44,4 +44,48 @@
       <version>${project.version}</version>
     </dependency>
   </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.jacoco</groupId>
+        <artifactId>jacoco-maven-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>jacoco-agent</id>
+            <goals>
+              <goal>prepare-agent</goal>
+            </goals>
+          </execution>
+          <execution>
+            <!--todo remove-->
+            <id>jacoco-report</id>
+            <phase>prepare-package</phase>
+            <goals>
+              <goal>report</goal>
+            </goals>
+          </execution>
+        </executions>
+        <configuration>
+          <propertyName>jacoco.agent</propertyName>
+        </configuration>
+      </plugin>
+      <plugin>
+        <artifactId>maven-surefire-plugin</artifactId>
+        <configuration>
+          <argLine>${jvm.args.tests} ${jacoco.agent}</argLine>
+          <includes>
+            <include>**/JUnit4SuiteTest.java</include>
+          </includes>
+        </configuration>
+        <dependencies>
+          <dependency>
+            <groupId>org.apache.maven.surefire</groupId>
+            <artifactId>surefire-shadefire</artifactId>
+            <version>3.0.0-M3</version> <!-- ${shadedVersion}, but resolved due to https://issues.apache.org/jira/browse/MRELEASE-799 -->
+          </dependency>
+        </dependencies>
+      </plugin>
+    </plugins>
+  </build>
 </project>
diff --git a/surefire-providers/surefire-junit4/src/test/java/org/apache/maven/surefire/junit4/JUnit4ProviderTest.java b/surefire-providers/surefire-junit4/src/test/java/org/apache/maven/surefire/junit4/JUnit4ProviderTest.java
index bf6cafc..2e411b9 100644
--- a/surefire-providers/surefire-junit4/src/test/java/org/apache/maven/surefire/junit4/JUnit4ProviderTest.java
+++ b/surefire-providers/surefire-junit4/src/test/java/org/apache/maven/surefire/junit4/JUnit4ProviderTest.java
@@ -19,9 +19,9 @@ package org.apache.maven.surefire.junit4;
  * under the License.
  */
 
-import junit.framework.TestCase;
 import org.apache.maven.surefire.booter.BaseProviderFactory;
 import org.apache.maven.surefire.testset.TestRequest;
+import org.junit.Test;
 import org.junit.runner.Description;
 
 import java.util.HashMap;
@@ -29,14 +29,15 @@ import java.util.HashMap;
 import static java.util.Arrays.asList;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.*;
+import static org.junit.Assert.assertNotNull;
 import static org.junit.runner.Description.createSuiteDescription;
 
 /**
  * @author Kristian Rosenvold
  */
 public class JUnit4ProviderTest
-    extends TestCase
 {
+    @Test
     public void testCreateProvider()
     {
         assertNotNull( getJUnit4Provider() );
@@ -51,6 +52,7 @@ public class JUnit4ProviderTest
         return new JUnit4Provider( providerParameters );
     }
 
+    @Test
     public void testShouldCreateDescription()
     {
         class A {
diff --git a/surefire-providers/common-junit48/src/test/java/org/apache/maven/surefire/common/junit48/JUnit4SuiteTest.java b/surefire-providers/surefire-junit4/src/test/java/org/apache/maven/surefire/junit4/JUnit4SuiteTest.java
similarity index 71%
copy from surefire-providers/common-junit48/src/test/java/org/apache/maven/surefire/common/junit48/JUnit4SuiteTest.java
copy to surefire-providers/surefire-junit4/src/test/java/org/apache/maven/surefire/junit4/JUnit4SuiteTest.java
index 547c381..2d4fb72 100644
--- a/surefire-providers/common-junit48/src/test/java/org/apache/maven/surefire/common/junit48/JUnit4SuiteTest.java
+++ b/surefire-providers/surefire-junit4/src/test/java/org/apache/maven/surefire/junit4/JUnit4SuiteTest.java
@@ -1,4 +1,4 @@
-package org.apache.maven.surefire.common.junit48;
+package org.apache.maven.surefire.junit4;
 
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
@@ -21,25 +21,15 @@ package org.apache.maven.surefire.common.junit48;
 
 import junit.framework.JUnit4TestAdapter;
 import junit.framework.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Suite;
+import junit.framework.TestCase;
 
 /**
  * Adapt the JUnit4 tests which use only annotations to the JUnit3 test suite.
- *
- * @author Tibor Digana (tibor17)
- * @since 2.19
  */
-@Suite.SuiteClasses( {
-    FilterFactoryTest.class,
-    JUnit48ReflectorTest.class,
-    JUnit48TestCheckerTest.class
-} )
-@RunWith( Suite.class )
-public class JUnit4SuiteTest
+public class JUnit4SuiteTest extends TestCase
 {
     public static Test suite()
     {
-        return new JUnit4TestAdapter( JUnit4SuiteTest.class );
+        return new JUnit4TestAdapter( JUnit4ProviderTest.class );
     }
 }
diff --git a/surefire-providers/surefire-junit47/pom.xml b/surefire-providers/surefire-junit47/pom.xml
index 2c36b5a..af32cc0 100644
--- a/surefire-providers/surefire-junit47/pom.xml
+++ b/surefire-providers/surefire-junit47/pom.xml
@@ -59,6 +59,29 @@
     <build>
         <plugins>
             <plugin>
+                <groupId>org.jacoco</groupId>
+                <artifactId>jacoco-maven-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>jacoco-agent</id>
+                        <goals>
+                            <goal>prepare-agent</goal>
+                        </goals>
+                    </execution>
+                    <execution>
+                        <!--todo remove-->
+                        <id>jacoco-report</id>
+                        <phase>prepare-package</phase>
+                        <goals>
+                            <goal>report</goal>
+                        </goals>
+                    </execution>
+                </executions>
+                <configuration>
+                    <propertyName>jacoco.agent</propertyName>
+                </configuration>
+            </plugin>
+            <plugin>
                 <artifactId>maven-dependency-plugin</artifactId>
                 <executions>
                     <execution>
@@ -155,11 +178,19 @@
             <plugin>
                 <artifactId>maven-surefire-plugin</artifactId>
                 <configuration>
+                    <argLine>${jvm.args.tests} ${jacoco.agent}</argLine>
                     <redirectTestOutputToFile>true</redirectTestOutputToFile>
                     <includes>
                         <include>**/JUnit47SuiteTest.java</include>
                     </includes>
                 </configuration>
+                <dependencies>
+                    <dependency>
+                        <groupId>org.apache.maven.surefire</groupId>
+                        <artifactId>surefire-shadefire</artifactId>
+                        <version>3.0.0-M3</version> <!-- ${shadedVersion}, but resolved due to https://issues.apache.org/jira/browse/MRELEASE-799 -->
+                    </dependency>
+                </dependencies>
             </plugin>
         </plugins>
     </build>
diff --git a/surefire-providers/surefire-junit47/src/test/java/org/apache/maven/surefire/junitcore/JUnit47SuiteTest.java b/surefire-providers/surefire-junit47/src/test/java/org/apache/maven/surefire/junitcore/JUnit47SuiteTest.java
index 9954627..02534ee 100644
--- a/surefire-providers/surefire-junit47/src/test/java/org/apache/maven/surefire/junitcore/JUnit47SuiteTest.java
+++ b/surefire-providers/surefire-junit47/src/test/java/org/apache/maven/surefire/junitcore/JUnit47SuiteTest.java
@@ -21,12 +21,12 @@ package org.apache.maven.surefire.junitcore;
 
 import junit.framework.JUnit4TestAdapter;
 import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
 import org.apache.maven.surefire.junitcore.pc.OptimizedParallelComputerTest;
 import org.apache.maven.surefire.junitcore.pc.ParallelComputerBuilderTest;
 import org.apache.maven.surefire.junitcore.pc.ParallelComputerUtilTest;
 import org.apache.maven.surefire.junitcore.pc.SchedulingStrategiesTest;
-import org.junit.runner.RunWith;
-import org.junit.runners.Suite;
 
 /**
  * Adapt the JUnit47 tests which use only annotations to the JUnit3 test suite.
@@ -34,27 +34,25 @@ import org.junit.runners.Suite;
  * @author Tibor Digana (tibor17)
  * @since 2.16
  */
-@Suite.SuiteClasses( {
-    Surefire746Test.class,
-    Surefire813IncorrectResultTest.class,
-    ParallelComputerUtilTest.class,
-    ParallelComputerBuilderTest.class,
-    SchedulingStrategiesTest.class,
-    OptimizedParallelComputerTest.class,
-    ConcurrentRunListenerTest.class,
-    ConfigurableParallelComputerTest.class,
-    JUnit4Reflector481Test.class,
-    JUnitCoreParametersTest.class,
-    JUnitCoreRunListenerTest.class,
-    MavenSurefireJUnit47RunnerTest.class,
-    MavenSurefireJUnit48RunnerTest.class,
-    TestMethodTest.class
-} )
-@RunWith( Suite.class )
-public class JUnit47SuiteTest
+public class JUnit47SuiteTest extends TestCase
 {
     public static Test suite()
     {
-        return new JUnit4TestAdapter( JUnit47SuiteTest.class );
+        TestSuite suite = new TestSuite();
+        suite.addTestSuite( ConcurrentRunListenerTest.class );
+        suite.addTestSuite( ConfigurableParallelComputerTest.class );
+        suite.addTestSuite( JUnitCoreRunListenerTest.class );
+        suite.addTestSuite( MavenSurefireJUnit47RunnerTest.class );
+        suite.addTestSuite( MavenSurefireJUnit48RunnerTest.class );
+        suite.addTestSuite( TestMethodTest.class );
+        suite.addTest( new JUnit4TestAdapter( Surefire746Test.class ) );
+        suite.addTest( new JUnit4TestAdapter( Surefire813IncorrectResultTest.class ) );
+        suite.addTest( new JUnit4TestAdapter( ParallelComputerUtilTest.class ) );
+        suite.addTest( new JUnit4TestAdapter( ParallelComputerBuilderTest.class ) );
+        suite.addTest( new JUnit4TestAdapter( SchedulingStrategiesTest.class ) );
+        suite.addTest( new JUnit4TestAdapter( OptimizedParallelComputerTest.class ) );
+        suite.addTest( new JUnit4TestAdapter( JUnit4Reflector481Test.class ) );
+        suite.addTest( new JUnit4TestAdapter( JUnitCoreParametersTest.class ) );
+        return suite;
     }
 }
diff --git a/surefire-providers/surefire-testng-utils/pom.xml b/surefire-providers/surefire-testng-utils/pom.xml
index b75979c..bfc4b55 100644
--- a/surefire-providers/surefire-testng-utils/pom.xml
+++ b/surefire-providers/surefire-testng-utils/pom.xml
@@ -55,7 +55,33 @@
   <build>
     <plugins>
       <plugin>
+        <groupId>org.jacoco</groupId>
+        <artifactId>jacoco-maven-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>jacoco-agent</id>
+            <goals>
+              <goal>prepare-agent</goal>
+            </goals>
+          </execution>
+          <execution>
+            <!--todo remove-->
+            <id>jacoco-report</id>
+            <phase>prepare-package</phase>
+            <goals>
+              <goal>report</goal>
+            </goals>
+          </execution>
+        </executions>
+        <configuration>
+          <propertyName>jacoco.agent</propertyName>
+        </configuration>
+      </plugin>
+      <plugin>
         <artifactId>maven-surefire-plugin</artifactId>
+        <configuration>
+          <argLine>${jvm.args.tests} ${jacoco.agent}</argLine>
+        </configuration>
         <dependencies>
           <dependency>
             <groupId>org.apache.maven.surefire</groupId>
diff --git a/surefire-providers/surefire-testng/pom.xml b/surefire-providers/surefire-testng/pom.xml
index 8c29441..d3d308d 100644
--- a/surefire-providers/surefire-testng/pom.xml
+++ b/surefire-providers/surefire-testng/pom.xml
@@ -60,7 +60,33 @@
   <build>
     <plugins>
       <plugin>
+        <groupId>org.jacoco</groupId>
+        <artifactId>jacoco-maven-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>jacoco-agent</id>
+            <goals>
+              <goal>prepare-agent</goal>
+            </goals>
+          </execution>
+          <execution>
+            <!--todo remove-->
+            <id>jacoco-report</id>
+            <phase>prepare-package</phase>
+            <goals>
+              <goal>report</goal>
+            </goals>
+          </execution>
+        </executions>
+        <configuration>
+          <propertyName>jacoco.agent</propertyName>
+        </configuration>
+      </plugin>
+      <plugin>
         <artifactId>maven-surefire-plugin</artifactId>
+        <configuration>
+          <argLine>${jvm.args.tests} ${jacoco.agent}</argLine>
+        </configuration>
         <dependencies>
           <dependency>
             <groupId>org.apache.maven.surefire</groupId>
diff --git a/surefire-report-parser/pom.xml b/surefire-report-parser/pom.xml
index 8c3f767..d1e2854 100644
--- a/surefire-report-parser/pom.xml
+++ b/surefire-report-parser/pom.xml
@@ -54,6 +54,29 @@
   <build>
     <plugins>
       <plugin>
+        <groupId>org.jacoco</groupId>
+        <artifactId>jacoco-maven-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>jacoco-agent</id>
+            <goals>
+              <goal>prepare-agent</goal>
+            </goals>
+          </execution>
+          <execution>
+            <!--todo remove-->
+            <id>jacoco-report</id>
+            <phase>prepare-package</phase>
+            <goals>
+              <goal>report</goal>
+            </goals>
+          </execution>
+        </executions>
+        <configuration>
+          <propertyName>jacoco.agent</propertyName>
+        </configuration>
+      </plugin>
+      <plugin>
         <artifactId>maven-surefire-plugin</artifactId>
         <dependencies>
           <dependency>
@@ -63,6 +86,7 @@
           </dependency>
         </dependencies>
         <configuration>
+          <argLine>${jvm.args.tests} ${jacoco.agent}</argLine>
           <includes>
             <include>**/JUnit4SuiteTest.java</include>
           </includes>
diff --git a/surefire-report-parser/src/test/java/org/apache/maven/plugins/surefire/report/JUnit4SuiteTest.java b/surefire-report-parser/src/test/java/org/apache/maven/plugins/surefire/report/JUnit4SuiteTest.java
index 142ca9d..8c143dd 100644
--- a/surefire-report-parser/src/test/java/org/apache/maven/plugins/surefire/report/JUnit4SuiteTest.java
+++ b/surefire-report-parser/src/test/java/org/apache/maven/plugins/surefire/report/JUnit4SuiteTest.java
@@ -21,8 +21,8 @@ package org.apache.maven.plugins.surefire.report;
 
 import junit.framework.JUnit4TestAdapter;
 import junit.framework.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Suite;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
 
 /**
  * Adapt the JUnit4 tests which use only annotations to the JUnit3 test suite.
@@ -30,17 +30,15 @@ import org.junit.runners.Suite;
  * @author Tibor Digana (tibor17)
  * @since 2.21.0
  */
-@Suite.SuiteClasses( {
-        ReportTestCaseTest.class,
-        ReportTestSuiteTest.class,
-        SurefireReportParserTest.class,
-        TestSuiteXmlParserTest.class
-} )
-@RunWith( Suite.class )
-public class JUnit4SuiteTest
+public class JUnit4SuiteTest extends TestCase
 {
     public static Test suite()
     {
-        return new JUnit4TestAdapter( JUnit4SuiteTest.class );
+        TestSuite suite = new TestSuite();
+        suite.addTestSuite( ReportTestCaseTest.class );
+        suite.addTestSuite( ReportTestSuiteTest.class );
+        suite.addTestSuite( SurefireReportParserTest.class );
+        suite.addTest( new JUnit4TestAdapter( TestSuiteXmlParserTest.class ) );
+        return suite;
     }
 }