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/01/26 22:41:09 UTC

[maven-surefire] branch junit5-displayname updated (0430ee0 -> d51a09c)

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

tibordigana pushed a change to branch junit5-displayname
in repository https://gitbox.apache.org/repos/asf/maven-surefire.git.


 discard 0430ee0  new ByteArrayInputStream( content.getBytes( UTF_8 ) ) in unit test
 discard 496f4a2  [SUREFIRE-1546] JUnit 5 runner does not honor JUnit 5 display names
     add cdd6225  maven '3.6.x' and jdk 12 on linux/windows
     add bba341d  [SUREFIRE-1534] ClassNotFoundException: org.apache.maven.plugin.surefire.StartupReportConfiguration using reuseForks set to false
     add 56d41b4  renamed assumeJigsaw() to assumeJava9()
     add c10f0cc  build fix - performance test (TestNGParallelTest) on slow system
     add e603af1  Upgrade maven-invoker-plugin:3.2.0
     add 1a186a1  avoided 16 executors on Jenkins - only 2 Mvn x 4 JDKs = 8
     new d51a09c  [SUREFIRE-1546] JUnit 5 runner does not honor JUnit 5 display names

This update added new revisions after undoing existing revisions.
That is to say, some revisions that were in the old version of the
branch are not in the new version.  This situation occurs
when a user --force pushes a change and generates a repository
containing something like this:

 * -- * -- B -- O -- O -- O   (0430ee0)
            \
             N -- N -- N   refs/heads/junit5-displayname (d51a09c)

You should already have received notification emails for all of the O
revisions, and so the following emails describe only the N revisions
from the common base, B.

Any revisions marked "omit" are not gone; other references still
refer to them.  Any revisions marked "discard" are gone forever.

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 Jenkinsfile                                        |  15 ++-
 .../plugin/surefire/AbstractSurefireMojo.java      |   8 +-
 .../AbstractSurefireMojoJava7PlusTest.java         |  29 ++++--
 .../ModularClasspathForkConfigurationTest.java     |   3 +-
 pom.xml                                            |   2 +-
 .../maven/surefire/report/SimpleReportEntry.java   |   2 +-
 .../surefire/booter/AbstractPathConfiguration.java |  20 ++--
 .../booter/ModularClasspathConfiguration.java      |  24 +++++
 .../maven/surefire/its/AbstractJigsawIT.java       |   2 +-
 .../apache/maven/surefire/its/Java9FullApiIT.java  |   2 +-
 .../apache/maven/surefire/its/ModulePathIT.java    |   4 +-
 .../surefire/its/jiras/Surefire1265Java9IT.java    |   2 +-
 ...urefire1534ReuseForksFalseWithJavaModuleIT.java | 100 ++++++++++++++++++
 .../pom.xml                                        |  31 ++++--
 .../src/main/java/it/Main.java                     |  17 ++++
 .../src/main/java/module-info.java                 |   4 +
 .../src/test/java/it/MainTest.java                 |  29 ++++++
 .../TestNGParallelTest.java                        |  31 +++---
 .../surefire/junitplatform/RunListenerAdapter.java |  90 +++++++++++------
 .../junitplatform/JUnitPlatformProviderTest.java   |  30 +++++-
 .../junitplatform/RunListenerAdapterTest.java      | 112 +++++++++++++++++----
 21 files changed, 447 insertions(+), 110 deletions(-)
 create mode 100644 surefire-its/src/test/java/org/apache/maven/surefire/its/jiras/Surefire1534ReuseForksFalseWithJavaModuleIT.java
 copy surefire-its/src/test/resources/{junit-platform-engine-vintage => surefire-1534-reuse-forks-false-java-module}/pom.xml (72%)
 create mode 100644 surefire-its/src/test/resources/surefire-1534-reuse-forks-false-java-module/src/main/java/it/Main.java
 create mode 100644 surefire-its/src/test/resources/surefire-1534-reuse-forks-false-java-module/src/main/java/module-info.java
 create mode 100644 surefire-its/src/test/resources/surefire-1534-reuse-forks-false-java-module/src/test/java/it/MainTest.java


[maven-surefire] 01/01: [SUREFIRE-1546] JUnit 5 runner does not honor JUnit 5 display names

Posted by ti...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit d51a09c901f75052af84b27d0abdfcef8530519b
Author: tibordigana <ti...@apache.org>
AuthorDate: Sat Jan 5 15:48:30 2019 +0100

    [SUREFIRE-1546] JUnit 5 runner does not honor JUnit 5 display names
---
 .../surefire/StartupReportConfiguration.java       |   8 +-
 .../surefire/report/ConsoleOutputFileReporter.java |   2 +-
 .../maven/plugin/surefire/report/FileReporter.java |   4 +-
 .../surefire/report/StatelessXmlReporter.java      | 318 +++++++++++----------
 .../plugin/surefire/report/WrappedReportEntry.java |  15 +-
 .../surefire/runorder/StatisticsReporter.java      |   5 +-
 .../surefire/report/StatelessXmlReporterTest.java  |  85 +++---
 .../surefire/report/WrappedReportEntryTest.java    |  24 +-
 .../runorder/RunEntryStatisticsMapTest.java        | 128 ++++++++-
 pom.xml                                            |   4 +-
 .../surefire/runorder/RunEntryStatistics.java      |  47 +--
 .../surefire/runorder/RunEntryStatisticsMap.java   | 172 +++++++----
 .../maven/surefire/booter/ForkingRunListener.java  |   2 +-
 .../surefire/report/CategorizedReportEntry.java    |   4 +-
 .../apache/maven/surefire/report/ReportEntry.java  |  10 +-
 .../maven/surefire/report/SimpleReportEntry.java   |  41 ++-
 .../maven/surefire/util/internal}/ClassMethod.java |  32 ++-
 .../util/internal/TestClassMethodNameUtils.java    |  32 ++-
 .../runorder/ThreadedExecutionSchedulerTest.java   |  26 +-
 surefire-its/pom.xml                               |   2 +-
 .../surefire/its/JUnit4RerunFailingTestsIT.java    |   4 +-
 .../maven/surefire/its/JUnitPlatformEnginesIT.java |   8 +-
 .../Surefire1152RerunFailingTestsInSuiteIT.java    |   8 +-
 .../its/jiras/Surefire1209RerunAndForkCountIT.java |  36 +--
 .../its/jiras/Surefire943ReportContentIT.java      |   5 +-
 ...g.apache.maven.surefire.test.SucceedingTest.xml |  68 -----
 .../org.apache.maven.surefire.test.FailingTest.txt |  84 ------
 ...g.apache.maven.surefire.test.SucceedingTest.txt |   4 -
 ...refireReport.surefireReportTest.MyClassTest.xml |   0
 ...refireReport.surefireReportTest.MyClassTest.txt |   2 +-
 ...refireReport.surefireReportTest.MyClassTest.xml |   4 +-
 ...refireReport.surefireReportTest.MyClassTest.txt |   2 +-
 .../surefire-570-multipleReportDirectories/pom.xml |   4 +-
 .../surefire/report/PojoStackTraceWriter.java      |  24 ++
 .../surefire/common/junit4/JUnit4ProviderUtil.java |  38 +--
 .../surefire/common/junit4/JUnit4Reflector.java    |   2 +-
 .../surefire/common/junit4/JUnit4RunListener.java  |  55 +---
 .../common/junit4/JUnit4StackTraceWriter.java      |  23 +-
 .../maven/surefire/common/junit4/Notifier.java     |   4 +-
 .../common/junit4/JUnit4ProviderUtilTest.java      |  15 +-
 .../common/junit48/JUnit46StackTraceWriter.java    |  60 ----
 surefire-providers/surefire-junit-platform/pom.xml |   4 +
 .../surefire/junitplatform/RunListenerAdapter.java | 303 ++++++++++----------
 .../surefire/junitplatform/JUnit47SuiteTest.java}  |  45 ++-
 .../junitplatform/JUnitPlatformProviderTest.java   |  57 ++--
 .../junitplatform/RunListenerAdapterTest.java      | 223 +++++++++++----
 .../maven/surefire/junit/JUnit3Provider.java       |   2 +-
 .../junit/TestListenerInvocationHandler.java       |  41 ++-
 .../maven/surefire/junit/JUnitTestSetTest.java     |  12 +-
 .../maven/surefire/junit4/JUnit4Provider.java      |   2 +-
 .../maven/surefire/junit4/TestResolverFilter.java  |   2 +-
 .../surefire/junitcore/JUnitCoreRunListener.java   |  20 +-
 .../junitcore/NonConcurrentRunListener.java        |  21 +-
 .../junitcore/JUnitCoreRunListenerTest.java        |   2 -
 .../maven/surefire/testng/TestNGReporter.java      |  32 +--
 .../apache/maven/surefire/testng/TestSuite.java    |   4 +-
 .../surefire/report/SurefireReportParser.java      |  29 +-
 .../surefire/report/SurefireReportParserTest.java  |  42 +--
 .../test-reports/com.shape.CircleTest.txt          |  16 +-
 .../test-reports/com.shapeclone.CircleTest.txt     |  16 +-
 60 files changed, 1140 insertions(+), 1144 deletions(-)

diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/StartupReportConfiguration.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/StartupReportConfiguration.java
index 5089973..932eecd 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/StartupReportConfiguration.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/StartupReportConfiguration.java
@@ -31,7 +31,7 @@ import javax.annotation.Nonnull;
 import java.io.File;
 import java.io.PrintStream;
 import java.nio.charset.Charset;
-import java.util.List;
+import java.util.Deque;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 
@@ -76,7 +76,7 @@ public final class StartupReportConfiguration
 
     private final String xsdSchemaLocation;
 
-    private final Map<String, Map<String, List<WrappedReportEntry>>> testClassMethodRunHistory
+    private final Map<String, Deque<WrappedReportEntry>> testClassMethodRunHistory
         = new ConcurrentHashMap<>();
 
     private final Charset encoding;
@@ -160,9 +160,9 @@ public final class StartupReportConfiguration
         // reporter, see Surefire1535TestNGParallelSuitesIT. The testClassMethodRunHistory should be isolated.
         // In the in-plugin execution of parallel JUnit4.7 with rerun the map must be shared because reports and
         // listeners are in ThreadLocal, see Surefire1122ParallelAndFlakyTestsIT.
-        Map<String, Map<String, List<WrappedReportEntry>>> testClassMethodRunHistory
+        Map<String, Deque<WrappedReportEntry>> testClassMethodRunHistory
                 = isForkMode
-                ? new ConcurrentHashMap<String, Map<String, List<WrappedReportEntry>>>()
+                ? new ConcurrentHashMap<String, Deque<WrappedReportEntry>>()
                 : this.testClassMethodRunHistory;
 
         return isDisableXmlReport()
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/ConsoleOutputFileReporter.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/ConsoleOutputFileReporter.java
index 0ea0a78..f6645b1 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/ConsoleOutputFileReporter.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/ConsoleOutputFileReporter.java
@@ -150,7 +150,7 @@ public class ConsoleOutputFileReporter
         finally
         {
             // prepare <class>-output.txt report file
-            reportEntryName = reportEntry.getName();
+            reportEntryName = reportEntry.getSourceName();
         }
     }
 
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/FileReporter.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/FileReporter.java
index 5d25e6a..941b88a 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/FileReporter.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/FileReporter.java
@@ -62,7 +62,7 @@ public class FileReporter
 
     public void testSetCompleted( WrappedReportEntry report, TestSetStats testSetStats, List<String> testResults )
     {
-        File reportFile = getReportFile( reportsDirectory, report.getName(), reportNameSuffix, ".txt" );
+        File reportFile = getReportFile( reportsDirectory, report.getSourceName(), reportNameSuffix, ".txt" );
 
         File reportDir = reportFile.getParentFile();
 
@@ -74,7 +74,7 @@ public class FileReporter
             writer.write( "-------------------------------------------------------------------------------" );
             writer.newLine();
 
-            writer.write( "Test set: " + report.getName() );
+            writer.write( "Test set: " + report.getSourceName() );
             writer.newLine();
 
             writer.write( "-------------------------------------------------------------------------------" );
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/StatelessXmlReporter.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/StatelessXmlReporter.java
index b89c4e9..c54943c 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/StatelessXmlReporter.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/StatelessXmlReporter.java
@@ -33,13 +33,14 @@ import java.io.FilterOutputStream;
 import java.io.IOException;
 import java.io.OutputStream;
 import java.io.OutputStreamWriter;
+import java.util.Deque;
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.StringTokenizer;
+import java.util.concurrent.ConcurrentLinkedDeque;
 
 import static java.nio.charset.StandardCharsets.UTF_8;
 import static org.apache.maven.plugin.surefire.report.DefaultReporterFactory.TestResultType;
@@ -96,11 +97,11 @@ public class StatelessXmlReporter
 
     // Map between test class name and a map between test method name
     // and the list of runs for each test method
-    private final Map<String, Map<String, List<WrappedReportEntry>>> testClassMethodRunHistoryMap;
+    private final Map<String, Deque<WrappedReportEntry>> testClassMethodRunHistoryMap;
 
     public StatelessXmlReporter( File reportsDirectory, String reportNameSuffix, boolean trimStackTrace,
                                  int rerunFailingTestsCount,
-                                 Map<String, Map<String, List<WrappedReportEntry>>> testClassMethodRunHistoryMap,
+                                 Map<String, Deque<WrappedReportEntry>> testClassMethodRunHistoryMap,
                                  String xsdSchemaLocation )
     {
         this.reportsDirectory = reportsDirectory;
@@ -113,15 +114,8 @@ public class StatelessXmlReporter
 
     public void testSetCompleted( WrappedReportEntry testSetReportEntry, TestSetStats testSetStats )
     {
-        String testClassName = testSetReportEntry.getName();
-
-        Map<String, List<WrappedReportEntry>> methodRunHistoryMap = getAddMethodRunHistoryMap( testClassName );
-
-        // Update testClassMethodRunHistoryMap
-        for ( WrappedReportEntry methodEntry : testSetStats.getReportEntries() )
-        {
-            getAddMethodEntryList( methodRunHistoryMap, methodEntry );
-        }
+        Map<String, Map<String, List<WrappedReportEntry>>> classMethodStatistics =
+                arrangeMethodStatistics( testSetReportEntry, testSetStats );
 
         OutputStream outputStream = getOutputStream( testSetReportEntry );
         try ( OutputStreamWriter fw = getWriter( outputStream ) )
@@ -129,111 +123,18 @@ public class StatelessXmlReporter
             XMLWriter ppw = new PrettyPrintXMLWriter( fw );
             ppw.setEncoding( UTF_8.name() );
 
-            createTestSuiteElement( ppw, testSetReportEntry, testSetStats, testSetReportEntry.elapsedTimeAsString() );
+            createTestSuiteElement( ppw, testSetReportEntry, testSetStats ); // TestSuite
 
             showProperties( ppw, testSetReportEntry.getSystemProperties() );
 
-            // Iterate through all the test methods in the test class
-            for ( Entry<String, List<WrappedReportEntry>> entry : methodRunHistoryMap.entrySet() )
+            for ( Entry<String, Map<String, List<WrappedReportEntry>>> statistics : classMethodStatistics.entrySet() )
             {
-                List<WrappedReportEntry> methodEntryList = entry.getValue();
-                if ( methodEntryList == null )
-                {
-                    throw new IllegalStateException( "Get null test method run history" );
-                }
-
-                if ( !methodEntryList.isEmpty() )
+                for ( Entry<String, List<WrappedReportEntry>> thisMethodRuns : statistics.getValue().entrySet() )
                 {
-                    if ( rerunFailingTestsCount > 0 )
-                    {
-                        switch ( getTestResultType( methodEntryList ) )
-                        {
-                            case success:
-                                for ( WrappedReportEntry methodEntry : methodEntryList )
-                                {
-                                    if ( methodEntry.getReportEntryType() == SUCCESS )
-                                    {
-                                        startTestElement( ppw, methodEntry, reportNameSuffix,
-                                                methodEntryList.get( 0 ).elapsedTimeAsString() );
-                                        ppw.endElement();
-                                    }
-                                }
-                                break;
-                            case error:
-                            case failure:
-                                // When rerunFailingTestsCount is set to larger than 0
-                                startTestElement( ppw, methodEntryList.get( 0 ), reportNameSuffix,
-                                        methodEntryList.get( 0 ).elapsedTimeAsString() );
-                                boolean firstRun = true;
-                                for ( WrappedReportEntry singleRunEntry : methodEntryList )
-                                {
-                                    if ( firstRun )
-                                    {
-                                        firstRun = false;
-                                        getTestProblems( fw, ppw, singleRunEntry, trimStackTrace, outputStream,
-                                                singleRunEntry.getReportEntryType().getXmlTag(), false );
-                                        createOutErrElements( fw, ppw, singleRunEntry, outputStream );
-                                    }
-                                    else
-                                    {
-                                        getTestProblems( fw, ppw, singleRunEntry, trimStackTrace, outputStream,
-                                                singleRunEntry.getReportEntryType().getRerunXmlTag(), true );
-                                    }
-                                }
-                                ppw.endElement();
-                                break;
-                            case flake:
-                                String runtime = "";
-                                // Get the run time of the first successful run
-                                for ( WrappedReportEntry singleRunEntry : methodEntryList )
-                                {
-                                    if ( singleRunEntry.getReportEntryType() == SUCCESS )
-                                    {
-                                        runtime = singleRunEntry.elapsedTimeAsString();
-                                        break;
-                                    }
-                                }
-                                startTestElement( ppw, methodEntryList.get( 0 ), reportNameSuffix, runtime );
-                                for ( WrappedReportEntry singleRunEntry : methodEntryList )
-                                {
-                                    if ( singleRunEntry.getReportEntryType() != SUCCESS )
-                                    {
-                                        getTestProblems( fw, ppw, singleRunEntry, trimStackTrace, outputStream,
-                                                singleRunEntry.getReportEntryType().getFlakyXmlTag(), true );
-                                    }
-                                }
-                                ppw.endElement();
-
-                                break;
-                            case skipped:
-                                startTestElement( ppw, methodEntryList.get( 0 ), reportNameSuffix,
-                                        methodEntryList.get( 0 ).elapsedTimeAsString() );
-                                getTestProblems( fw, ppw, methodEntryList.get( 0 ), trimStackTrace, outputStream,
-                                        methodEntryList.get( 0 ).getReportEntryType().getXmlTag(), false );
-                                ppw.endElement();
-                                break;
-                            default:
-                                throw new IllegalStateException( "Get unknown test result type" );
-                        }
-                    }
-                    else
-                    {
-                        // rerunFailingTestsCount is smaller than 1, but for some reasons a test could be run
-                        // for more than once
-                        for ( WrappedReportEntry methodEntry : methodEntryList )
-                        {
-                            startTestElement( ppw, methodEntry, reportNameSuffix, methodEntry.elapsedTimeAsString() );
-                            if ( methodEntry.getReportEntryType() != SUCCESS )
-                            {
-                                getTestProblems( fw, ppw, methodEntry, trimStackTrace, outputStream,
-                                        methodEntry.getReportEntryType().getXmlTag(), false );
-                                createOutErrElements( fw, ppw, methodEntry, outputStream );
-                            }
-                            ppw.endElement();
-                        }
-                    }
+                    serializeTestClass( outputStream, fw, ppw, thisMethodRuns.getValue() );
                 }
             }
+
             ppw.endElement(); // TestSuite
         }
         catch ( Exception e )
@@ -246,6 +147,143 @@ public class StatelessXmlReporter
         }
     }
 
+    private Map<String, Map<String, List<WrappedReportEntry>>> arrangeMethodStatistics(
+            WrappedReportEntry testSetReportEntry, TestSetStats testSetStats )
+    {
+        Map<String, Map<String, List<WrappedReportEntry>>> classMethodStatistics = new LinkedHashMap<>();
+        for ( WrappedReportEntry methodEntry : aggregateCacheFromMultipleReruns( testSetReportEntry, testSetStats ) )
+        {
+            String testClassName = methodEntry.getSourceName();
+            Map<String, List<WrappedReportEntry>> stats = classMethodStatistics.get( testClassName );
+            if ( stats == null )
+            {
+                stats = new LinkedHashMap<>();
+                classMethodStatistics.put( testClassName, stats );
+            }
+            String methodName = methodEntry.getName();
+            List<WrappedReportEntry> methodRuns = stats.get( methodName );
+            if ( methodRuns == null )
+            {
+                methodRuns = new ArrayList<>();
+                stats.put( methodName, methodRuns );
+            }
+            methodRuns.add( methodEntry );
+        }
+        return classMethodStatistics;
+    }
+
+    private Deque<WrappedReportEntry> aggregateCacheFromMultipleReruns( WrappedReportEntry testSetReportEntry,
+                                                                       TestSetStats testSetStats )
+    {
+        String suiteClassName = testSetReportEntry.getSourceName();
+        Deque<WrappedReportEntry> methodRunHistory = getAddMethodRunHistoryMap( suiteClassName );
+        methodRunHistory.addAll( testSetStats.getReportEntries() );
+        return methodRunHistory;
+    }
+
+    private void serializeTestClass( OutputStream outputStream, OutputStreamWriter fw, XMLWriter ppw,
+                                     List<WrappedReportEntry> methodEntries )
+    {
+        if ( rerunFailingTestsCount > 0 )
+        {
+            serializeTestClassWithRerun( outputStream, fw, ppw, methodEntries );
+        }
+        else
+        {
+            // rerunFailingTestsCount is smaller than 1, but for some reasons a test could be run
+            // for more than once
+            serializeTestClassWithoutRerun( outputStream, fw, ppw, methodEntries );
+        }
+    }
+
+    private void serializeTestClassWithoutRerun( OutputStream outputStream, OutputStreamWriter fw, XMLWriter ppw,
+                                                 List<WrappedReportEntry> methodEntries )
+    {
+        for ( WrappedReportEntry methodEntry : methodEntries )
+        {
+            startTestElement( ppw, methodEntry );
+            if ( methodEntry.getReportEntryType() != SUCCESS )
+            {
+                getTestProblems( fw, ppw, methodEntry, trimStackTrace, outputStream,
+                        methodEntry.getReportEntryType().getXmlTag(), false );
+                createOutErrElements( fw, ppw, methodEntry, outputStream );
+            }
+            ppw.endElement();
+        }
+    }
+
+    private void serializeTestClassWithRerun( OutputStream outputStream, OutputStreamWriter fw, XMLWriter ppw,
+                                              List<WrappedReportEntry> methodEntries )
+    {
+        WrappedReportEntry firstMethodEntry = methodEntries.get( 0 );
+        switch ( getTestResultType( methodEntries ) )
+        {
+            case success:
+                for ( WrappedReportEntry methodEntry : methodEntries )
+                {
+                    if ( methodEntry.getReportEntryType() == SUCCESS )
+                    {
+                        startTestElement( ppw, methodEntry );
+                        ppw.endElement();
+                    }
+                }
+                break;
+            case error:
+            case failure:
+                // When rerunFailingTestsCount is set to larger than 0
+                startTestElement( ppw, firstMethodEntry );
+                boolean firstRun = true;
+                for ( WrappedReportEntry singleRunEntry : methodEntries )
+                {
+                    if ( firstRun )
+                    {
+                        firstRun = false;
+                        getTestProblems( fw, ppw, singleRunEntry, trimStackTrace, outputStream,
+                                singleRunEntry.getReportEntryType().getXmlTag(), false );
+                        createOutErrElements( fw, ppw, singleRunEntry, outputStream );
+                    }
+                    else
+                    {
+                        getTestProblems( fw, ppw, singleRunEntry, trimStackTrace, outputStream,
+                                singleRunEntry.getReportEntryType().getRerunXmlTag(), true );
+                    }
+                }
+                ppw.endElement();
+                break;
+            case flake:
+                WrappedReportEntry successful = null;
+                // Get the run time of the first successful run
+                for ( WrappedReportEntry singleRunEntry : methodEntries )
+                {
+                    if ( singleRunEntry.getReportEntryType() == SUCCESS )
+                    {
+                        successful = singleRunEntry;
+                        break;
+                    }
+                }
+                WrappedReportEntry firstOrSuccessful = successful == null ? methodEntries.get( 0 ) : successful;
+                startTestElement( ppw, firstOrSuccessful );
+                for ( WrappedReportEntry singleRunEntry : methodEntries )
+                {
+                    if ( singleRunEntry.getReportEntryType() != SUCCESS )
+                    {
+                        getTestProblems( fw, ppw, singleRunEntry, trimStackTrace, outputStream,
+                                singleRunEntry.getReportEntryType().getFlakyXmlTag(), true );
+                    }
+                }
+                ppw.endElement();
+                break;
+            case skipped:
+                startTestElement( ppw, firstMethodEntry );
+                getTestProblems( fw, ppw, firstMethodEntry, trimStackTrace, outputStream,
+                        firstMethodEntry.getReportEntryType().getXmlTag(), false );
+                ppw.endElement();
+                break;
+            default:
+                throw new IllegalStateException( "Get unknown test result type" );
+        }
+    }
+
     /**
      * Clean testClassMethodRunHistoryMap
      */
@@ -271,20 +309,20 @@ public class StatelessXmlReporter
         return DefaultReporterFactory.getTestResultType( testResultTypeList, rerunFailingTestsCount );
     }
 
-    private Map<String, List<WrappedReportEntry>> getAddMethodRunHistoryMap( String testClassName )
+    private Deque<WrappedReportEntry> getAddMethodRunHistoryMap( String testClassName )
     {
-        Map<String, List<WrappedReportEntry>> methodRunHistoryMap = testClassMethodRunHistoryMap.get( testClassName );
-        if ( methodRunHistoryMap == null )
+        Deque<WrappedReportEntry> methodRunHistory = testClassMethodRunHistoryMap.get( testClassName );
+        if ( methodRunHistory == null )
         {
-            methodRunHistoryMap = Collections.synchronizedMap( new LinkedHashMap<String, List<WrappedReportEntry>>() );
-            testClassMethodRunHistoryMap.put( testClassName, methodRunHistoryMap );
+            methodRunHistory = new ConcurrentLinkedDeque<>();
+            testClassMethodRunHistoryMap.put( testClassName == null ? "null" : testClassName, methodRunHistory );
         }
-        return methodRunHistoryMap;
+        return methodRunHistory;
     }
 
     private OutputStream getOutputStream( WrappedReportEntry testSetReportEntry )
     {
-        File reportFile = getReportFile( testSetReportEntry, reportsDirectory, reportNameSuffix );
+        File reportFile = getReportFile( testSetReportEntry );
 
         File reportDir = reportFile.getParentFile();
 
@@ -306,50 +344,33 @@ public class StatelessXmlReporter
         return new OutputStreamWriter( fos, UTF_8 );
     }
 
-    private static void getAddMethodEntryList( Map<String, List<WrappedReportEntry>> methodRunHistoryMap,
-                                               WrappedReportEntry methodEntry )
+    private File getReportFile( ReportEntry report )
     {
-        List<WrappedReportEntry> methodEntryList = methodRunHistoryMap.get( methodEntry.getName() );
-        if ( methodEntryList == null )
-        {
-            methodEntryList = new ArrayList<>();
-            methodRunHistoryMap.put( methodEntry.getName(), methodEntryList );
-        }
-        methodEntryList.add( methodEntry );
-    }
-
-    private static File getReportFile( ReportEntry report, File reportsDirectory, String reportNameSuffix )
-    {
-        String reportName = "TEST-" + report.getName();
+        String reportName = "TEST-" + report.getSourceName();
         String customizedReportName = isBlank( reportNameSuffix ) ? reportName : reportName + "-" + reportNameSuffix;
         return new File( reportsDirectory, stripIllegalFilenameChars( customizedReportName + ".xml" ) );
     }
 
-    private static void startTestElement( XMLWriter ppw, WrappedReportEntry report, String reportNameSuffix,
-                                          String timeAsString )
+    private void startTestElement( XMLWriter ppw, WrappedReportEntry report )
     {
         ppw.startElement( "testcase" );
-        ppw.addAttribute( "name", report.getReportName() );
+        ppw.addAttribute( "name", report.getName() == null ? "" : extraEscape( report.getName(), true ) );
+
         if ( report.getGroup() != null )
         {
             ppw.addAttribute( "group", report.getGroup() );
         }
-        if ( report.getSourceName() != null )
+
+        String className = report.getReportName( reportNameSuffix );
+        if ( className != null )
         {
-            if ( reportNameSuffix != null && !reportNameSuffix.isEmpty() )
-            {
-                ppw.addAttribute( "classname", report.getSourceName() + "(" + reportNameSuffix + ")" );
-            }
-            else
-            {
-                ppw.addAttribute( "classname", report.getSourceName() );
-            }
+            ppw.addAttribute( "classname", extraEscape( className, true ) );
         }
-        ppw.addAttribute( "time", timeAsString );
+
+        ppw.addAttribute( "time", report.elapsedTimeAsString() );
     }
 
-    private void createTestSuiteElement( XMLWriter ppw, WrappedReportEntry report, TestSetStats testSetStats,
-                                         String timeAsString )
+    private void createTestSuiteElement( XMLWriter ppw, WrappedReportEntry report, TestSetStats testSetStats )
     {
         ppw.startElement( "testsuite" );
 
@@ -357,14 +378,15 @@ public class StatelessXmlReporter
         ppw.addAttribute( "xsi:noNamespaceSchemaLocation", xsdSchemaLocation );
         ppw.addAttribute( "version", "3.0" );
 
-        ppw.addAttribute( "name", report.getReportName( reportNameSuffix ) );
+        String reportName = report.getReportName( reportNameSuffix );
+        ppw.addAttribute( "name", reportName == null ? "" : extraEscape( reportName, true ) );
 
         if ( report.getGroup() != null )
         {
             ppw.addAttribute( "group", report.getGroup() );
         }
 
-        ppw.addAttribute( "time", timeAsString );
+        ppw.addAttribute( "time", report.elapsedTimeAsString() );
 
         ppw.addAttribute( "tests", String.valueOf( testSetStats.getCompletedCount() ) );
 
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/WrappedReportEntry.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/WrappedReportEntry.java
index 3426e3a..efec3a6 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/WrappedReportEntry.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/WrappedReportEntry.java
@@ -28,6 +28,7 @@ import java.util.Map;
 
 import static java.util.Collections.unmodifiableMap;
 import static org.apache.maven.plugin.surefire.report.ReporterUtils.formatElapsedTime;
+import static org.apache.maven.surefire.util.internal.StringUtils.isBlank;
 import static org.apache.maven.surefire.util.internal.StringUtils.NL;
 
 /**
@@ -74,6 +75,12 @@ public class WrappedReportEntry
         return elapsed;
     }
 
+    @Override
+    public int getElapsed( int fallback )
+    {
+        return elapsed == null ? fallback : elapsed;
+    }
+
     public ReportEntryType getReportEntryType()
     {
         return reportEntryType;
@@ -137,13 +144,12 @@ public class WrappedReportEntry
 
     public String getReportName()
     {
-        final int i = getName().lastIndexOf( "(" );
-        return i > 0 ? getName().substring( 0, i ) : getName();
+        return getSourceName();
     }
 
     public String getReportName( String suffix )
     {
-        return suffix != null && !suffix.isEmpty() ? getReportName() + "(" + suffix + ")" : getReportName();
+        return isBlank( suffix ) ? getReportName() : getReportName() + "(" + suffix + ")";
     }
 
     public String getOutput( boolean trimStackTrace )
@@ -160,7 +166,8 @@ public class WrappedReportEntry
 
     public String getElapsedTimeSummary()
     {
-        return getName() + "  " + getElapsedTimeVerbose();
+        String description = getName() == null ? getSourceName() : getClassMethodName();
+        return description + "  " + getElapsedTimeVerbose();
     }
 
     public boolean isErrorOrFailure()
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/runorder/StatisticsReporter.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/runorder/StatisticsReporter.java
index a53db02..2d9a175 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/runorder/StatisticsReporter.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/runorder/StatisticsReporter.java
@@ -20,7 +20,8 @@ package org.apache.maven.plugin.surefire.runorder;
  */
 
 import java.io.File;
-import java.io.FileNotFoundException;
+import java.io.IOException;
+
 import org.apache.maven.surefire.report.ReportEntry;
 
 import static org.apache.maven.plugin.surefire.runorder.RunEntryStatisticsMap.fromFile;
@@ -54,7 +55,7 @@ public class StatisticsReporter
         {
             newResults.serialize( dataFile );
         }
-        catch ( FileNotFoundException e )
+        catch ( IOException e )
         {
             throw new RuntimeException( e );
         }
diff --git a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/report/StatelessXmlReporterTest.java b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/report/StatelessXmlReporterTest.java
index 6e6f3d5..315b75f 100644
--- a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/report/StatelessXmlReporterTest.java
+++ b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/report/StatelessXmlReporterTest.java
@@ -32,9 +32,8 @@ import java.io.File;
 import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStreamReader;
+import java.util.Deque;
 import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.atomic.AtomicInteger;
 
@@ -43,7 +42,7 @@ import static org.apache.maven.surefire.util.internal.ObjectUtils.systemProps;
 
 @SuppressWarnings( "ResultOfMethodCallIgnored" )
 public class StatelessXmlReporterTest
-    extends TestCase
+        extends TestCase
 {
     private static final String XSD =
             "https://maven.apache.org/surefire/maven-surefire-plugin/xsd/surefire-test-report-3.0.xsd";
@@ -59,7 +58,7 @@ public class StatelessXmlReporterTest
 
     @Override
     protected void setUp()
-        throws Exception
+            throws Exception
     {
         stats = new TestSetStats( false, true );
         rerunStats = new TestSetStats( false, true );
@@ -84,29 +83,29 @@ public class StatelessXmlReporterTest
     public void testFileNameWithoutSuffix()
     {
         StatelessXmlReporter reporter =
-            new StatelessXmlReporter( reportDir, null, false, 0,
-                                      new ConcurrentHashMap<String, Map<String, List<WrappedReportEntry>>>(), XSD );
+                new StatelessXmlReporter( reportDir, null, false, 0,
+                        new ConcurrentHashMap<String, Deque<WrappedReportEntry>>(), XSD );
         reporter.cleanTestHistoryMap();
 
         ReportEntry reportEntry = new SimpleReportEntry( getClass().getName(), getClass().getName(), 12 );
-        WrappedReportEntry testSetReportEntry =
-            new WrappedReportEntry( reportEntry, ReportEntryType.SUCCESS, 12, null, null, systemProps() );
+        WrappedReportEntry testSetReportEntry = new WrappedReportEntry( reportEntry, ReportEntryType.SUCCESS,
+                12, null, null, systemProps() );
         stats.testSucceeded( testSetReportEntry );
         reporter.testSetCompleted( testSetReportEntry, stats );
 
         expectedReportFile = new File( reportDir, "TEST-" + getClass().getName() + ".xml" );
         assertTrue( "Report file (" + expectedReportFile.getAbsolutePath() + ") doesn't exist",
-                    expectedReportFile.exists() );
+                expectedReportFile.exists() );
     }
 
 
     public void testAllFieldsSerialized()
-        throws IOException
+            throws IOException
     {
         ReportEntry reportEntry = new SimpleReportEntry( getClass().getName(), TEST_ONE, 12 );
         WrappedReportEntry testSetReportEntry =
-            new WrappedReportEntry( reportEntry, ReportEntryType.SUCCESS, 12, null, null, systemProps() );
-        expectedReportFile = new File( reportDir, "TEST-" + TEST_ONE + ".xml" );
+                new WrappedReportEntry( reportEntry, ReportEntryType.SUCCESS, 12, null, null, systemProps() );
+        expectedReportFile = new File( reportDir, "TEST-" + getClass().getName() + ".xml" );
 
         stats.testSucceeded( testSetReportEntry );
         StackTraceWriter stackTraceWriter = new DeserializedStacktraceWriter( "A fud msg", "trimmed", "fail at foo" );
@@ -133,12 +132,12 @@ public class StatelessXmlReporterTest
         byte[] stdErrBytes = (stdErrPrefix + "?&-&amp;&#163;\u0020\u0000\u001F").getBytes();
         stdErr.write( stdErrBytes, 0, stdErrBytes.length );
         WrappedReportEntry t2 =
-            new WrappedReportEntry( new SimpleReportEntry( Inner.class.getName(), TEST_TWO, stackTraceWriter, 13 ),
-                                    ReportEntryType.ERROR, 13, stdOut, stdErr );
+                new WrappedReportEntry( new SimpleReportEntry( getClass().getName(), TEST_TWO, stackTraceWriter, 13 ),
+                        ReportEntryType.ERROR, 13, stdOut, stdErr );
 
         stats.testSucceeded( t2 );
         StatelessXmlReporter reporter = new StatelessXmlReporter( reportDir, null, false, 0,
-                        new ConcurrentHashMap<String, Map<String, List<WrappedReportEntry>>>(), XSD );
+                new ConcurrentHashMap<String, Deque<WrappedReportEntry>>(), XSD );
         reporter.testSetCompleted( testSetReportEntry, stats );
 
         FileInputStream fileInputStream = new FileInputStream( expectedReportFile );
@@ -153,14 +152,14 @@ public class StatelessXmlReporterTest
 
         Xpp3Dom[] testcase = testSuite.getChildren( "testcase" );
         Xpp3Dom tca = testcase[0];
-        assertEquals( TEST_ONE, tca.getAttribute( "name" ) ); // Hopefully same order on jdk5
+        assertEquals( TEST_ONE, tca.getAttribute( "name" ) );
         assertEquals( "0.012", tca.getAttribute( "time" ) );
         assertEquals( getClass().getName(), tca.getAttribute( "classname" ) );
 
         Xpp3Dom tcb = testcase[1];
         assertEquals( TEST_TWO, tcb.getAttribute( "name" ) );
         assertEquals( "0.013", tcb.getAttribute( "time" ) );
-        assertEquals( Inner.class.getName(), tcb.getAttribute( "classname" ) );
+        assertEquals( getClass().getName(), tcb.getAttribute( "classname" ) );
         Xpp3Dom errorNode = tcb.getChild( "error" );
         assertNotNull( errorNode );
         assertEquals( "A fud msg", errorNode.getAttribute( "message" ) );
@@ -172,19 +171,18 @@ public class StatelessXmlReporterTest
     }
 
     public void testOutputRerunFlakyFailure()
-        throws IOException
+            throws IOException
     {
-        ReportEntry reportEntry = new SimpleReportEntry( getClass().getName(), TEST_ONE, 12 );
-
         WrappedReportEntry testSetReportEntry =
-            new WrappedReportEntry( reportEntry, ReportEntryType.SUCCESS, 12, null, null, systemProps() );
-        expectedReportFile = new File( reportDir, "TEST-" + TEST_ONE + ".xml" );
+                new WrappedReportEntry( new SimpleReportEntry( getClass().getName(), TEST_ONE, 12 ),
+                        ReportEntryType.SUCCESS, 12, null, null, systemProps() );
+        expectedReportFile = new File( reportDir, "TEST-" + getClass().getName() + ".xml" );
 
         stats.testSucceeded( testSetReportEntry );
         StackTraceWriter stackTraceWriterOne = new DeserializedStacktraceWriter( "A fud msg", "trimmed",
-                                                                                 "fail at foo" );
+                "fail at foo" );
         StackTraceWriter stackTraceWriterTwo =
-            new DeserializedStacktraceWriter( "A fud msg two", "trimmed two", "fail at foo two" );
+                new DeserializedStacktraceWriter( "A fud msg two", "trimmed two", "fail at foo two" );
 
         String firstRunOut = "first run out";
         String firstRunErr = "first run err";
@@ -192,24 +190,24 @@ public class StatelessXmlReporterTest
         String secondRunErr = "second run err";
 
         WrappedReportEntry testTwoFirstError =
-            new WrappedReportEntry( new SimpleReportEntry( Inner.class.getName(), TEST_TWO, stackTraceWriterOne, 5 ),
-                                    ReportEntryType.ERROR, 5, createStdOutput( firstRunOut ),
-                                    createStdOutput( firstRunErr ) );
+                new WrappedReportEntry( new SimpleReportEntry( getClass().getName(), TEST_TWO, stackTraceWriterOne, 5 ),
+                        ReportEntryType.ERROR, 5, createStdOutput( firstRunOut ),
+                        createStdOutput( firstRunErr ) );
 
         WrappedReportEntry testTwoSecondError =
-            new WrappedReportEntry( new SimpleReportEntry( Inner.class.getName(), TEST_TWO, stackTraceWriterTwo, 13 ),
-                                    ReportEntryType.ERROR, 13, createStdOutput( secondRunOut ),
-                                    createStdOutput( secondRunErr ) );
+                new WrappedReportEntry( new SimpleReportEntry( getClass().getName(), TEST_TWO, stackTraceWriterTwo, 13 ),
+                        ReportEntryType.ERROR, 13, createStdOutput( secondRunOut ),
+                        createStdOutput( secondRunErr ) );
 
         WrappedReportEntry testThreeFirstRun =
-            new WrappedReportEntry( new SimpleReportEntry( Inner.class.getName(), TEST_THREE, stackTraceWriterOne, 13 ),
-                                    ReportEntryType.FAILURE, 13, createStdOutput( firstRunOut ),
-                                    createStdOutput( firstRunErr ) );
+                new WrappedReportEntry( new SimpleReportEntry( getClass().getName(), TEST_THREE, stackTraceWriterOne, 13 ),
+                        ReportEntryType.FAILURE, 13, createStdOutput( firstRunOut ),
+                        createStdOutput( firstRunErr ) );
 
         WrappedReportEntry testThreeSecondRun =
-            new WrappedReportEntry( new SimpleReportEntry( Inner.class.getName(), TEST_THREE, stackTraceWriterTwo, 2 ),
-                                    ReportEntryType.SUCCESS, 2, createStdOutput( secondRunOut ),
-                                    createStdOutput( secondRunErr ) );
+                new WrappedReportEntry( new SimpleReportEntry( getClass().getName(), TEST_THREE, stackTraceWriterTwo, 2 ),
+                        ReportEntryType.SUCCESS, 2, createStdOutput( secondRunOut ),
+                        createStdOutput( secondRunErr ) );
 
         stats.testSucceeded( testTwoFirstError );
         stats.testSucceeded( testThreeFirstRun );
@@ -217,8 +215,8 @@ public class StatelessXmlReporterTest
         rerunStats.testSucceeded( testThreeSecondRun );
 
         StatelessXmlReporter reporter =
-            new StatelessXmlReporter( reportDir, null, false, 1,
-                                      new HashMap<String, Map<String, List<WrappedReportEntry>>>(), XSD );
+                new StatelessXmlReporter( reportDir, null, false, 1,
+                        new HashMap<String, Deque<WrappedReportEntry>>(), XSD );
 
         reporter.testSetCompleted( testSetReportEntry, stats );
         reporter.testSetCompleted( testSetReportEntry, rerunStats );
@@ -244,7 +242,7 @@ public class StatelessXmlReporterTest
         assertEquals( TEST_TWO, testCaseTwo.getAttribute( "name" ) );
         // Run time for a rerun failing test is the run time of the first run
         assertEquals( "0.005", testCaseTwo.getAttribute( "time" ) );
-        assertEquals( Inner.class.getName(), testCaseTwo.getAttribute( "classname" ) );
+        assertEquals( getClass().getName(), testCaseTwo.getAttribute( "classname" ) );
         Xpp3Dom errorNode = testCaseTwo.getChild( "error" );
         Xpp3Dom rerunErrorNode = testCaseTwo.getChild( "rerunError" );
         assertNotNull( errorNode );
@@ -266,7 +264,7 @@ public class StatelessXmlReporterTest
         assertEquals( TEST_THREE, testCaseThree.getAttribute( "name" ) );
         // Run time for a flaky test is the run time of the first successful run
         assertEquals( "0.002", testCaseThree.getAttribute( "time" ) );
-        assertEquals( Inner.class.getName(), testCaseThree.getAttribute( "classname" ) );
+        assertEquals( getClass().getName(), testCaseThree.getAttribute( "classname" ) );
         Xpp3Dom flakyFailureNode = testCaseThree.getChild( "flakyFailure" );
         assertNotNull( flakyFailureNode );
         assertEquals( firstRunOut, flakyFailureNode.getChild( "system-out" ).getValue() );
@@ -283,15 +281,10 @@ public class StatelessXmlReporterTest
     }
 
     private Utf8RecodingDeferredFileOutputStream createStdOutput( String content )
-        throws IOException
+            throws IOException
     {
         Utf8RecodingDeferredFileOutputStream stdOut = new Utf8RecodingDeferredFileOutputStream( "fds2" );
         stdOut.write( content.getBytes(), 0, content.length() );
         return stdOut;
     }
-
-    class Inner
-    {
-
-    }
 }
diff --git a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/report/WrappedReportEntryTest.java b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/report/WrappedReportEntryTest.java
index 030fc2f..61080a1 100644
--- a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/report/WrappedReportEntryTest.java
+++ b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/report/WrappedReportEntryTest.java
@@ -29,45 +29,39 @@ import junit.framework.TestCase;
 public class WrappedReportEntryTest
     extends TestCase
 {
-
     public void testClassNameOnly()
-        throws Exception
     {
-        String category = "surefire.testcase.JunitParamsTest";
+        String className = "surefire.testcase.JunitParamsTest";
         WrappedReportEntry wr =
-            new WrappedReportEntry( new SimpleReportEntry( "fud", category ), null, 12, null, null );
+            new WrappedReportEntry( new SimpleReportEntry( className, null ), null, 12, null, null );
         final String reportName = wr.getReportName();
         assertEquals( "surefire.testcase.JunitParamsTest", reportName );
     }
 
     public void testRegular()
     {
-        ReportEntry reportEntry = new SimpleReportEntry( "fud", "testSum(surefire.testcase.NonJunitParamsTest)" );
+        ReportEntry reportEntry = new SimpleReportEntry( "surefire.testcase.JunitParamsTest", "testSum" );
         WrappedReportEntry wr = new WrappedReportEntry( reportEntry, null, 12, null, null );
         final String reportName = wr.getReportName();
-        assertEquals( "testSum", reportName );
+        assertEquals( "surefire.testcase.JunitParamsTest", reportName );
     }
 
     public void testGetReportNameWithParams()
-        throws Exception
     {
-        String category = "[0] 1\u002C 2\u002C 3 (testSum)(surefire.testcase.JunitParamsTest)";
-        ReportEntry reportEntry = new SimpleReportEntry( "fud", category );
+        String className = "[0] 1\u002C 2\u002C 3 (testSum)";
+        ReportEntry reportEntry = new SimpleReportEntry( className, null );
         WrappedReportEntry wr = new WrappedReportEntry( reportEntry, null, 12, null, null );
         final String reportName = wr.getReportName();
         assertEquals( "[0] 1, 2, 3 (testSum)", reportName );
     }
 
     public void testElapsed()
-        throws Exception
     {
-        String category = "[0] 1\u002C 2\u002C 3 (testSum)(surefire.testcase.JunitParamsTest)";
-        ReportEntry reportEntry = new SimpleReportEntry( "fud", category );
+        String className = "[0] 1\u002C 2\u002C 3 (testSum)";
+        ReportEntry reportEntry = new SimpleReportEntry( className, null );
         WrappedReportEntry wr = new WrappedReportEntry( reportEntry, null, 12, null, null );
         String elapsedTimeSummary = wr.getElapsedTimeSummary();
-        assertEquals( "[0] 1, 2, 3 (testSum)(surefire.testcase.JunitParamsTest)  Time elapsed: 0.012 s",
+        assertEquals( "[0] 1, 2, 3 (testSum)  Time elapsed: 0.012 s",
                       elapsedTimeSummary );
     }
-
-
 }
diff --git a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/runorder/RunEntryStatisticsMapTest.java b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/runorder/RunEntryStatisticsMapTest.java
index 5a171ab..2970356 100644
--- a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/runorder/RunEntryStatisticsMapTest.java
+++ b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/runorder/RunEntryStatisticsMapTest.java
@@ -19,16 +19,24 @@ package org.apache.maven.plugin.surefire.runorder;
  * under the License.
  */
 
+import java.io.ByteArrayInputStream;
 import java.io.File;
+import java.io.FileInputStream;
 import java.io.IOException;
-import java.io.StringReader;
+import java.io.InputStream;
 import java.util.Arrays;
 import java.util.List;
+
 import org.apache.maven.surefire.report.ReportEntry;
 import org.apache.maven.surefire.report.SimpleReportEntry;
 
 import junit.framework.TestCase;
 
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.apache.commons.io.IOUtils.readLines;
+import static org.apache.maven.surefire.util.internal.StringUtils.NL;
+import static org.fest.assertions.Assertions.assertThat;
+
 /**
  * @author Kristian Rosenvold
  */
@@ -36,9 +44,8 @@ public class RunEntryStatisticsMapTest
     extends TestCase
 {
     public void testPrioritizedClassRuntime()
-        throws IOException
     {
-        final RunEntryStatisticsMap runEntryStatisticsMap = RunEntryStatisticsMap.fromReader( getStatisticsFile() );
+        final RunEntryStatisticsMap runEntryStatisticsMap = RunEntryStatisticsMap.fromStream( getStatisticsFile() );
         final List<Class<?>> list = Arrays.<Class<?>>asList( A.class, B.class, C.class );
         final List<Class<?>> prioritizedTestsClassRunTime =
             runEntryStatisticsMap.getPrioritizedTestsClassRunTime( list, 2 );
@@ -48,9 +55,8 @@ public class RunEntryStatisticsMapTest
     }
 
     public void testPrioritizedFailureFirst()
-        throws IOException
     {
-        final RunEntryStatisticsMap runEntryStatisticsMap = RunEntryStatisticsMap.fromReader( getStatisticsFile() );
+        final RunEntryStatisticsMap runEntryStatisticsMap = RunEntryStatisticsMap.fromStream( getStatisticsFile() );
         final List<Class<?>> list = Arrays.<Class<?>>asList( A.class, B.class, NewClass.class, C.class );
         final List<Class<?>> prioritizedTestsClassRunTime =
             runEntryStatisticsMap.getPrioritizedTestsByFailureFirst( list );
@@ -60,12 +66,12 @@ public class RunEntryStatisticsMapTest
         assertEquals( B.class, prioritizedTestsClassRunTime.get( 3 ) );
     }
 
-    private StringReader getStatisticsFile()
+    private InputStream getStatisticsFile()
     {
-        String content = "0,17,testA(org.apache.maven.plugin.surefire.runorder.RunEntryStatisticsMapTest$A)\n" +
-            "2,42,testB(org.apache.maven.plugin.surefire.runorder.RunEntryStatisticsMapTest$B)\n" +
-            "1,100,testC(org.apache.maven.plugin.surefire.runorder.RunEntryStatisticsMapTest$C)\n";
-        return new StringReader( content );
+        String content = "0,17,org.apache.maven.plugin.surefire.runorder.RunEntryStatisticsMapTest$A,testA\n"
+                + "2,42,org.apache.maven.plugin.surefire.runorder.RunEntryStatisticsMapTest$B,testB\n"
+                + "1,100,org.apache.maven.plugin.surefire.runorder.RunEntryStatisticsMapTest$C,testC\n";
+        return new ByteArrayInputStream( content.getBytes( UTF_8 ) );
     }
 
     public void testSerialize()
@@ -84,15 +90,111 @@ public class RunEntryStatisticsMapTest
         newResults.add( existingEntries.createNextGeneration( reportEntry3 ) );
 
         newResults.serialize( data );
+        try ( InputStream io = new FileInputStream( data) )
+        {
+            List<String> lines = readLines( io, UTF_8 );
+
+            assertThat( lines )
+                    .hasSize( 3 );
+
+            assertThat( lines )
+                    .containsSequence( "1,17,abc,willFail", "1,42,abc,method1", "1,100,abc,method3" );
+        }
 
         RunEntryStatisticsMap nextRun = RunEntryStatisticsMap.fromFile( data );
         newResults = new RunEntryStatisticsMap();
 
-        newResults.add( existingEntries.createNextGeneration( reportEntry1 ) );
-        newResults.add( existingEntries.createNextGenerationFailure( reportEntry2 ) );
-        newResults.add( existingEntries.createNextGeneration( reportEntry3 ) );
+        ReportEntry newRunReportEntry1 = new SimpleReportEntry( "abc", "method1", 52 );
+        ReportEntry newRunReportEntry2 = new SimpleReportEntry( "abc", "willFail", 27 );
+        ReportEntry newRunReportEntry3 = new SimpleReportEntry( "abc", "method3", 110 );
+
+        newResults.add( nextRun.createNextGeneration( newRunReportEntry1 ) );
+        newResults.add( nextRun.createNextGenerationFailure( newRunReportEntry2 ) );
+        newResults.add( nextRun.createNextGeneration( newRunReportEntry3 ) );
 
         newResults.serialize( data );
+        try ( InputStream io = new FileInputStream( data ) )
+        {
+            List<String> lines = readLines( io, UTF_8 );
+
+            assertThat( lines )
+                    .hasSize( 3 );
+
+            assertThat( lines )
+                    .containsSequence( "0,27,abc,willFail", "2,52,abc,method1", "2,110,abc,method3" );
+        }
+    }
+
+    public void testMultiLineTestMethodName() throws IOException
+    {
+        File data = File.createTempFile( "surefire-unit", "test" );
+        RunEntryStatisticsMap reportEntries = RunEntryStatisticsMap.fromFile( data );
+        ReportEntry reportEntry = new SimpleReportEntry( "abc", "line1\nline2" + NL + " line3", 42 );
+        reportEntries.add( reportEntries.createNextGeneration( reportEntry ) );
+
+        reportEntries.serialize( data );
+        try ( InputStream io = new FileInputStream( data ) )
+        {
+            List<String> lines = readLines( io, UTF_8 );
+
+            assertThat( lines )
+                    .hasSize( 3 );
+
+            assertThat( lines )
+                    .containsSequence( "1,42,abc,line1", " line2", "  line3" );
+        }
+
+        RunEntryStatisticsMap nextRun = RunEntryStatisticsMap.fromFile( data );
+        assertThat( data.delete() ).isTrue();
+        nextRun.serialize( data );
+        try ( InputStream io = new FileInputStream( data ) )
+        {
+            List<String> lines = readLines( io, UTF_8 );
+
+            assertThat( lines )
+                    .hasSize( 3 );
+
+            assertThat( lines )
+                    .containsSequence( "1,42,abc,line1", " line2", "  line3" );
+        }
+    }
+
+    public void testCombinedMethodNames() throws IOException
+    {
+        File data = File.createTempFile( "surefire-unit", "test" );
+        RunEntryStatisticsMap reportEntries = RunEntryStatisticsMap.fromFile( data );
+        reportEntries.add( reportEntries.createNextGeneration( new SimpleReportEntry( "abc", "line1\nline2", 42 ) ) );
+        reportEntries.add( reportEntries.createNextGeneration( new SimpleReportEntry( "abc", "test", 10 ) ) );
+
+        reportEntries.serialize( data );
+        try ( InputStream io = new FileInputStream( data ) )
+        {
+            List<String> lines = readLines( io, UTF_8 );
+
+            assertThat( lines )
+                    .hasSize( 3 );
+
+            assertThat( lines )
+                    .containsSequence( "1,10,abc,test",
+                                       "1,42,abc,line1",
+                                       " line2" );
+        }
+
+        RunEntryStatisticsMap nextRun = RunEntryStatisticsMap.fromFile( data );
+        assertThat( data.delete() ).isTrue();
+        nextRun.serialize( data );
+        try ( InputStream io = new FileInputStream( data ) )
+        {
+            List<String> lines = readLines( io, UTF_8 );
+
+            assertThat( lines )
+                    .hasSize( 3 );
+
+            assertThat( lines )
+                    .containsSequence( "1,10,abc,test",
+                                       "1,42,abc,line1",
+                                       " line2" );
+        }
     }
 
     class A
diff --git a/pom.xml b/pom.xml
index 0b8cf79..2b7a1e1 100644
--- a/pom.xml
+++ b/pom.xml
@@ -277,12 +277,12 @@
       <dependency>
         <groupId>org.junit.platform</groupId>
         <artifactId>junit-platform-launcher</artifactId>
-        <version>1.3.1</version>
+        <version>1.3.2</version>
       </dependency>
       <dependency>
         <groupId>org.junit.jupiter</groupId>
         <artifactId>junit-jupiter-engine</artifactId>
-        <version>5.3.1</version>
+        <version>5.3.2</version>
       </dependency>
       <dependency>
         <groupId>org.mockito</groupId>
diff --git a/surefire-api/src/main/java/org/apache/maven/plugin/surefire/runorder/RunEntryStatistics.java b/surefire-api/src/main/java/org/apache/maven/plugin/surefire/runorder/RunEntryStatistics.java
index 7c794dc..1ccc4ee 100644
--- a/surefire-api/src/main/java/org/apache/maven/plugin/surefire/runorder/RunEntryStatistics.java
+++ b/surefire-api/src/main/java/org/apache/maven/plugin/surefire/runorder/RunEntryStatistics.java
@@ -19,8 +19,7 @@ package org.apache.maven.plugin.surefire.runorder;
  * under the License.
  */
 
-import java.util.StringTokenizer;
-import org.apache.maven.surefire.report.ReportEntry;
+import org.apache.maven.surefire.util.internal.ClassMethod;
 
 /**
  * @author Kristian Rosenvold
@@ -31,39 +30,33 @@ public class RunEntryStatistics
 
     private final int successfulBuilds;
 
-    private final String testName;
+    private final ClassMethod classMethod;
 
-    private RunEntryStatistics( int runTime, int successfulBuilds, String testName )
+    RunEntryStatistics( int runTime, int successfulBuilds, String clazz, String method )
     {
-        this.runTime = runTime;
-        this.successfulBuilds = successfulBuilds;
-        this.testName = testName;
+        this( runTime, successfulBuilds, new ClassMethod( clazz, method ) );
     }
 
-    public static RunEntryStatistics fromReportEntry( ReportEntry previous )
+    RunEntryStatistics( int runTime, int successfulBuilds, ClassMethod classMethod )
     {
-        final Integer elapsed = previous.getElapsed();
-        return new RunEntryStatistics( elapsed != null ? elapsed : 0, 0, previous.getName() );
+        this.runTime = runTime;
+        this.successfulBuilds = successfulBuilds;
+        this.classMethod = classMethod;
     }
 
-    public static RunEntryStatistics fromValues( int runTime, int successfulBuilds, Class clazz, String testName )
+    public ClassMethod getClassMethod()
     {
-        return new RunEntryStatistics( runTime, successfulBuilds, testName + "(" + clazz.getName() + ")" );
+        return classMethod;
     }
 
     public RunEntryStatistics nextGeneration( int runTime )
     {
-        return new RunEntryStatistics( runTime, this.successfulBuilds + 1, this.testName );
+        return new RunEntryStatistics( runTime, successfulBuilds + 1, classMethod );
     }
 
     public RunEntryStatistics nextGenerationFailure( int runTime )
     {
-        return new RunEntryStatistics( runTime, 0, this.testName );
-    }
-
-    public String getTestName()
-    {
-        return testName;
+        return new RunEntryStatistics( runTime, 0, classMethod );
     }
 
     public int getRunTime()
@@ -75,20 +68,4 @@ public class RunEntryStatistics
     {
         return successfulBuilds;
     }
-
-    public static RunEntryStatistics fromString( String line )
-    {
-        StringTokenizer tok = new StringTokenizer( line, "," );
-        int successfulBuilds = Integer.parseInt( tok.nextToken() );
-        int runTime = Integer.parseInt( tok.nextToken() );
-        String className = tok.nextToken();
-        return new RunEntryStatistics( runTime, successfulBuilds, className );
-    }
-
-    @Override
-    public String toString()
-    {
-        return successfulBuilds + "," + runTime + "," + testName;
-    }
-
 }
diff --git a/surefire-api/src/main/java/org/apache/maven/plugin/surefire/runorder/RunEntryStatisticsMap.java b/surefire-api/src/main/java/org/apache/maven/plugin/surefire/runorder/RunEntryStatisticsMap.java
index 1a685dc..09a4445 100644
--- a/surefire-api/src/main/java/org/apache/maven/plugin/surefire/runorder/RunEntryStatisticsMap.java
+++ b/surefire-api/src/main/java/org/apache/maven/plugin/surefire/runorder/RunEntryStatisticsMap.java
@@ -19,38 +19,41 @@ package org.apache.maven.plugin.surefire.runorder;
  * under the License.
  */
 
-
 import org.apache.maven.surefire.report.ReportEntry;
+import org.apache.maven.surefire.util.internal.ClassMethod;
 
-import java.io.BufferedReader;
+import java.io.BufferedWriter;
 import java.io.File;
-import java.io.FileNotFoundException;
+import java.io.FileInputStream;
 import java.io.FileOutputStream;
-import java.io.FileReader;
 import java.io.IOException;
-import java.io.PrintWriter;
-import java.io.Reader;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
 import java.util.ArrayList;
 import java.util.Comparator;
 import java.util.HashMap;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Scanner;
+import java.util.StringTokenizer;
 import java.util.concurrent.ConcurrentHashMap;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
 
+import static java.lang.Integer.parseInt;
+import static java.nio.charset.StandardCharsets.UTF_8;
 import static java.util.Collections.sort;
-import static org.apache.maven.plugin.surefire.runorder.RunEntryStatistics.fromReportEntry;
-import static org.apache.maven.plugin.surefire.runorder.RunEntryStatistics.fromString;
+import static org.apache.maven.surefire.util.internal.StringUtils.NL;
 
 /**
  * @author Kristian Rosenvold
  */
 public final class RunEntryStatisticsMap
 {
-    private final Map<String, RunEntryStatistics> runEntryStatistics;
+    private final Map<ClassMethod, RunEntryStatistics> runEntryStatistics;
 
-    public RunEntryStatisticsMap( Map<String, RunEntryStatistics> runEntryStatistics )
+    private RunEntryStatisticsMap( Map<ClassMethod, RunEntryStatistics> runEntryStatistics )
     {
         this.runEntryStatistics = new ConcurrentHashMap<>( runEntryStatistics );
     }
@@ -66,7 +69,7 @@ public final class RunEntryStatisticsMap
         {
             try
             {
-                return fromReader( new FileReader( file ) );
+                return fromStream( new FileInputStream( file ) );
             }
             catch ( IOException e )
             {
@@ -79,62 +82,124 @@ public final class RunEntryStatisticsMap
         }
     }
 
-    static RunEntryStatisticsMap fromReader( Reader fileReader )
-        throws IOException
+    static RunEntryStatisticsMap fromStream( InputStream fileReader )
     {
-        Map<String, RunEntryStatistics> result = new HashMap<>();
-        BufferedReader bufferedReader = new BufferedReader( fileReader );
-        String line = bufferedReader.readLine();
-        while ( line != null )
+        Map<ClassMethod, RunEntryStatistics> result = new HashMap<>();
+        try ( Scanner scanner = new Scanner( fileReader, "UTF-8" ) )
         {
-            if ( !line.startsWith( "#" ) )
+            RunEntryStatistics previous = null;
+            while ( scanner.hasNextLine() )
             {
-                final RunEntryStatistics stats = fromString( line );
-                result.put( stats.getTestName(), stats );
+                String line = scanner.nextLine();
+
+                if ( line.charAt( 0 ) == ' ' )
+                {
+                    previous = new RunEntryStatistics( previous.getRunTime(),
+                            previous.getSuccessfulBuilds(),
+                            previous.getClassMethod().getClazz(),
+                            previous.getClassMethod().getMethod() + NL + line.substring( 1 ) );
+                }
+                else
+                {
+                    if ( previous != null )
+                    {
+                        result.put( previous.getClassMethod(), previous );
+                    }
+                    StringTokenizer tokenizer = new StringTokenizer( line, "," );
+
+                    int methodIndex = 3;
+
+                    String successfulBuildsString = tokenizer.nextToken();
+                    int successfulBuilds = parseInt( successfulBuildsString );
+
+                    methodIndex += successfulBuildsString.length();
+
+                    String runTimeString = tokenizer.nextToken();
+                    int runTime = parseInt( runTimeString );
+
+                    methodIndex += runTimeString.length();
+
+                    String className = tokenizer.nextToken();
+
+                    methodIndex += className.length();
+
+                    String methodName = line.substring( methodIndex );
+
+                    ClassMethod classMethod = new ClassMethod( className, methodName );
+                    previous = new RunEntryStatistics( runTime, successfulBuilds, classMethod );
+                }
+            }
+            if ( previous != null )
+            {
+                result.put( previous.getClassMethod(), previous );
             }
-            line = bufferedReader.readLine();
         }
         return new RunEntryStatisticsMap( result );
     }
 
-    public void serialize( File file )
-        throws FileNotFoundException
+    public void serialize( File statsFile )
+        throws IOException
     {
-        FileOutputStream fos = new FileOutputStream( file );
-        try ( PrintWriter printWriter = new PrintWriter( fos ) )
+        if ( statsFile.isFile() )
+        {
+            //noinspection ResultOfMethodCallIgnored
+            statsFile.delete();
+        }
+        OutputStream os = new FileOutputStream( statsFile );
+        try ( BufferedWriter writer = new BufferedWriter( new OutputStreamWriter( os, UTF_8 ), 64 * 1024 ) )
         {
             List<RunEntryStatistics> items = new ArrayList<>( runEntryStatistics.values() );
             sort( items, new RunCountComparator() );
-            for ( RunEntryStatistics item : items )
+            for ( Iterator<RunEntryStatistics> it = items.iterator(); it.hasNext(); )
             {
-                printWriter.println( item.toString() );
+                RunEntryStatistics item = it.next();
+                ClassMethod test = item.getClassMethod();
+                String line = item.getSuccessfulBuilds() + "," + item.getRunTime() + "," + test.getClazz() + ",";
+                writer.write( line );
+                boolean wasFirstLine = false;
+                for ( Scanner scanner = new Scanner( test.getMethod() ); scanner.hasNextLine(); wasFirstLine = true )
+                {
+                    String methodLine = scanner.nextLine();
+                    if ( wasFirstLine )
+                    {
+                        writer.write( ' ' );
+                    }
+                    writer.write( methodLine );
+                    if ( scanner.hasNextLine() )
+                    {
+                        writer.newLine();
+                    }
+                }
+                if ( it.hasNext() )
+                {
+                    writer.newLine();
+                }
             }
         }
     }
 
-    public RunEntryStatistics findOrCreate( ReportEntry reportEntry )
+    private RunEntryStatistics findOrCreate( ReportEntry reportEntry )
     {
-        final RunEntryStatistics item = runEntryStatistics.get( reportEntry.getName() );
-        return item != null ? item : fromReportEntry( reportEntry );
+        ClassMethod classMethod = new ClassMethod( reportEntry.getSourceName(), reportEntry.getName() );
+        RunEntryStatistics item = runEntryStatistics.get( classMethod );
+        return item != null ? item : new RunEntryStatistics( reportEntry.getElapsed( 0 ), 0, classMethod );
     }
 
     public RunEntryStatistics createNextGeneration( ReportEntry reportEntry )
     {
-        final RunEntryStatistics newItem = findOrCreate( reportEntry );
-        final Integer elapsed = reportEntry.getElapsed();
-        return newItem.nextGeneration( elapsed != null ? elapsed : 0 );
+        RunEntryStatistics newItem = findOrCreate( reportEntry );
+        return newItem.nextGeneration( reportEntry.getElapsed( 0 ) );
     }
 
     public RunEntryStatistics createNextGenerationFailure( ReportEntry reportEntry )
     {
-        final RunEntryStatistics newItem = findOrCreate( reportEntry );
-        final Integer elapsed = reportEntry.getElapsed();
-        return newItem.nextGenerationFailure( elapsed != null ? elapsed : 0 );
+        RunEntryStatistics newItem = findOrCreate( reportEntry );
+        return newItem.nextGenerationFailure( reportEntry.getElapsed( 0 ) );
     }
 
     public void add( RunEntryStatistics item )
     {
-        runEntryStatistics.put( item.getTestName(), item );
+        runEntryStatistics.put( item.getClassMethod(), item );
     }
 
     static final class RunCountComparator
@@ -169,12 +234,12 @@ public final class RunEntryStatisticsMap
     private List<PrioritizedTest> getPrioritizedTests( List<Class<?>> testsToRun,
                                                        Comparator<Priority> priorityComparator )
     {
-        Map classPriorities = getPriorities( priorityComparator );
+        Map<String, Priority> classPriorities = getPriorities( priorityComparator );
 
         List<PrioritizedTest> tests = new ArrayList<>();
         for ( Class<?> clazz : testsToRun )
         {
-            Priority pri = (Priority) classPriorities.get( clazz.getName() );
+            Priority pri = classPriorities.get( clazz.getName() );
             if ( pri == null )
             {
                 pri = Priority.newTestClassPriority( clazz.getName() );
@@ -186,7 +251,7 @@ public final class RunEntryStatisticsMap
         return tests;
     }
 
-    private List<Class<?>> transformToClasses( List<PrioritizedTest> tests )
+    private static List<Class<?>> transformToClasses( List<PrioritizedTest> tests )
     {
         List<Class<?>> result = new ArrayList<>();
         for ( PrioritizedTest test : tests )
@@ -196,22 +261,19 @@ public final class RunEntryStatisticsMap
         return result;
     }
 
-    private Map getPriorities( Comparator<Priority> priorityComparator )
+    private Map<String, Priority> getPriorities( Comparator<Priority> priorityComparator )
     {
         Map<String, Priority> priorities = new HashMap<>();
-        for ( Object o : runEntryStatistics.keySet() )
+        for ( Entry<ClassMethod, RunEntryStatistics> testNames : runEntryStatistics.entrySet() )
         {
-            String testNames = (String) o;
-            String clazzName = extractClassName( testNames );
+            String clazzName = testNames.getKey().getClazz();
             Priority priority = priorities.get( clazzName );
             if ( priority == null )
             {
                 priority = new Priority( clazzName );
                 priorities.put( clazzName, priority );
             }
-
-            RunEntryStatistics itemStat = runEntryStatistics.get( testNames );
-            priority.addItem( itemStat );
+            priority.addItem( testNames.getValue() );
         }
 
         List<Priority> items = new ArrayList<>( priorities.values() );
@@ -255,16 +317,4 @@ public final class RunEntryStatisticsMap
             return o.getMinSuccessRate() - o1.getMinSuccessRate();
         }
     }
-
-
-    private static final Pattern PARENS = Pattern.compile( "^" + "[^\\(\\)]+" //non-parens
-                                                               + "\\((" // then an open-paren (start matching a group)
-                                                               + "[^\\\\(\\\\)]+" //non-parens
-                                                               + ")\\)" + "$" ); // then a close-paren (end group match)
-
-    String extractClassName( String displayName )
-    {
-        Matcher m = PARENS.matcher( displayName );
-        return m.find() ? m.group( 1 ) : displayName;
-    }
 }
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/booter/ForkingRunListener.java b/surefire-api/src/main/java/org/apache/maven/surefire/booter/ForkingRunListener.java
index ce806b9..80d08db 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/booter/ForkingRunListener.java
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/booter/ForkingRunListener.java
@@ -417,7 +417,7 @@ public class ForkingRunListener
     @Override
     public void println( String message )
     {
-        byte[] buf = message.getBytes();
+        byte[] buf = ( message == null ? "null" : message ).getBytes();
         println( buf, 0, buf.length );
     }
 
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/report/CategorizedReportEntry.java b/surefire-api/src/main/java/org/apache/maven/surefire/report/CategorizedReportEntry.java
index 47b0c48..cad41a2 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/report/CategorizedReportEntry.java
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/report/CategorizedReportEntry.java
@@ -78,7 +78,7 @@ public class CategorizedReportEntry
     @Override
     public String getNameWithGroup()
     {
-        return isNameWithGroup() ? getName() + GROUP_PREFIX + getGroup() + GROUP_SUFIX : getName();
+        return isNameWithGroup() ? getSourceName() + GROUP_PREFIX + getGroup() + GROUP_SUFIX : getSourceName();
     }
 
     @Override
@@ -113,6 +113,6 @@ public class CategorizedReportEntry
 
     private boolean isNameWithGroup()
     {
-        return getGroup() != null && !getGroup().equals( getName() );
+        return getGroup() != null && !getGroup().equals( getSourceName() );
     }
 }
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/report/ReportEntry.java b/surefire-api/src/main/java/org/apache/maven/surefire/report/ReportEntry.java
index ec0f782..6e4a04a 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/report/ReportEntry.java
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/report/ReportEntry.java
@@ -61,6 +61,14 @@ public interface ReportEntry
      */
     Integer getElapsed();
 
+    /**
+     * Returns same value as {@link #getElapsed()} and fallbacks to {@code fallback} for <tt>null</tt> elapsed timed.
+     *
+     * @param fallback usually 0
+     * @return elapsed time if {@link #getElapsed()} is not null; otherwise returns {@code fallback}
+     */
+    int getElapsed( int fallback );
+
 
     /**
      * A message relating to a non-successful termination.
@@ -71,7 +79,7 @@ public interface ReportEntry
     String getMessage();
 
     /**
-     * A name of the test case together with the group or category (if any exists).
+     * A source name of the test case together with the group or category (if any exists).
      *
      * @return A string with the test case name and group/category, or just the name.
      */
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/report/SimpleReportEntry.java b/surefire-api/src/main/java/org/apache/maven/surefire/report/SimpleReportEntry.java
index 241c874..73e5f3b 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/report/SimpleReportEntry.java
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/report/SimpleReportEntry.java
@@ -23,6 +23,7 @@ import org.apache.maven.surefire.util.internal.ImmutableMap;
 
 import java.util.Collections;
 import java.util.Map;
+import java.util.Objects;
 
 /**
  * @author Kristian Rosenvold
@@ -75,25 +76,11 @@ public class SimpleReportEntry
     protected SimpleReportEntry( String source, String name, StackTraceWriter stackTraceWriter, Integer elapsed,
                                  String message, Map<String, String> systemProperties )
     {
-        if ( source == null )
-        {
-            source = "null";
-        }
-        if ( name == null )
-        {
-            name = "null";
-        }
-
         this.source = source;
-
         this.name = name;
-
         this.stackTraceWriter = stackTraceWriter;
-
         this.message = message;
-
         this.elapsed = elapsed;
-
         this.systemProperties = new ImmutableMap<>( systemProperties );
     }
 
@@ -167,10 +154,16 @@ public class SimpleReportEntry
     }
 
     @Override
+    public int getElapsed( int fallback )
+    {
+        return elapsed == null ? fallback : elapsed;
+    }
+
+    @Override
     public String toString()
     {
         return "ReportEntry{" + "source='" + source + '\'' + ", name='" + name + '\'' + ", stackTraceWriter="
-            + stackTraceWriter + ", elapsed=" + elapsed + ",message=" + message + '}';
+            + stackTraceWriter + ", elapsed=" + elapsed + ", message=" + message + '}';
     }
 
     @Override
@@ -198,17 +191,17 @@ public class SimpleReportEntry
     @Override
     public int hashCode()
     {
-        int result = source != null ? source.hashCode() : 0;
-        result = 31 * result + ( name != null ? name.hashCode() : 0 );
-        result = 31 * result + ( stackTraceWriter != null ? stackTraceWriter.hashCode() : 0 );
-        result = 31 * result + ( elapsed != null ? elapsed.hashCode() : 0 );
+        int result = Objects.hashCode( source );
+        result = 31 * result + Objects.hashCode( name );
+        result = 31 * result + Objects.hashCode( stackTraceWriter );
+        result = 31 * result + Objects.hashCode( elapsed );
         return result;
     }
 
     @Override
     public String getNameWithGroup()
     {
-        return getName();
+        return getSourceName();
     }
 
     @Override
@@ -219,21 +212,21 @@ public class SimpleReportEntry
 
     private boolean isElapsedTimeEqual( SimpleReportEntry en )
     {
-        return elapsed != null ? elapsed.equals( en.elapsed ) : en.elapsed == null;
+        return Objects.equals( elapsed, en.elapsed );
     }
 
     private boolean isNameEqual( SimpleReportEntry en )
     {
-        return name != null ? name.equals( en.name ) : en.name == null;
+        return Objects.equals( name, en.name );
     }
 
     private boolean isSourceEqual( SimpleReportEntry en )
     {
-        return source != null ? source.equals( en.source ) : en.source == null;
+        return Objects.equals( source, en.source );
     }
 
     private boolean isStackEqual( SimpleReportEntry en )
     {
-        return stackTraceWriter != null ? stackTraceWriter.equals( en.stackTraceWriter ) : en.stackTraceWriter == null;
+        return Objects.equals( stackTraceWriter, en.stackTraceWriter );
     }
 }
diff --git a/surefire-providers/common-junit4/src/main/java/org/apache/maven/surefire/common/junit4/ClassMethod.java b/surefire-api/src/main/java/org/apache/maven/surefire/util/internal/ClassMethod.java
similarity index 63%
copy from surefire-providers/common-junit4/src/main/java/org/apache/maven/surefire/common/junit4/ClassMethod.java
copy to surefire-api/src/main/java/org/apache/maven/surefire/util/internal/ClassMethod.java
index a3cccca..03f9620 100644
--- a/surefire-providers/common-junit4/src/main/java/org/apache/maven/surefire/common/junit4/ClassMethod.java
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/util/internal/ClassMethod.java
@@ -1,4 +1,4 @@
-package org.apache.maven.surefire.common.junit4;
+package org.apache.maven.surefire.util.internal;
 
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
@@ -19,7 +19,9 @@ package org.apache.maven.surefire.common.junit4;
  * under the License.
  */
 
-import org.apache.maven.surefire.util.internal.StringUtils;
+import java.util.Objects;
+
+import static org.apache.maven.surefire.util.internal.StringUtils.isBlank;
 
 /**
  * Data transfer object of class and method literals.
@@ -36,9 +38,9 @@ public final class ClassMethod
         this.method = method;
     }
 
-    public boolean isValid()
+    public boolean isValidTest()
     {
-        return !StringUtils.isBlank( clazz ) && !StringUtils.isBlank( method );
+        return !isBlank( clazz ) && !isBlank( method );
     }
 
     public String getClazz()
@@ -50,4 +52,26 @@ public final class ClassMethod
     {
         return method;
     }
+
+    @Override
+    public boolean equals( Object o )
+    {
+        if ( this == o )
+        {
+            return true;
+        }
+        if ( o == null || getClass() != o.getClass() )
+        {
+            return false;
+        }
+        ClassMethod that = ( ClassMethod ) o;
+        return Objects.equals( clazz, that.clazz )
+                && Objects.equals( method, that.method );
+    }
+
+    @Override
+    public int hashCode()
+    {
+        return Objects.hash( clazz, method );
+    }
 }
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/util/internal/TestClassMethodNameUtils.java b/surefire-api/src/main/java/org/apache/maven/surefire/util/internal/TestClassMethodNameUtils.java
index 23e72e1..94bf4c8 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/util/internal/TestClassMethodNameUtils.java
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/util/internal/TestClassMethodNameUtils.java
@@ -19,24 +19,15 @@ package org.apache.maven.surefire.util.internal;
  * under the License.
  */
 
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
 /**
  * JUnit Description parser.
- * Used by JUnit Version lower than 4.7.
+ * Used by JUnit4+.
  *
  * @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
  * @since 2.20
  */
 public final class TestClassMethodNameUtils
 {
-    /**
-     * This pattern is verbatim copy from JUnit's code in class {@code Description}.
-     * Parsing class and method from junit description would provide identical result to JUnit internal parser.
-     */
-    private static final Pattern METHOD_CLASS_PATTERN = Pattern.compile( "([\\s\\S]*)\\((.*)\\)" );
-
     private TestClassMethodNameUtils()
     {
         throw new IllegalStateException( "no instantiable constructor" );
@@ -44,13 +35,26 @@ public final class TestClassMethodNameUtils
 
     public static String extractClassName( String displayName )
     {
-        Matcher m = METHOD_CLASS_PATTERN.matcher( displayName );
-        return m.matches() ? m.group( 2 ) : displayName;
+        String clazz = displayName;
+        if ( displayName.endsWith( ")" ) )
+        {
+            int paren = displayName.lastIndexOf( '(' );
+            if ( paren != -1 )
+            {
+                clazz = displayName.substring( paren + 1, displayName.length() - 1 );
+            }
+        }
+        return clazz;
     }
 
     public static String extractMethodName( String displayName )
     {
-        Matcher m = METHOD_CLASS_PATTERN.matcher( displayName );
-        return m.matches() ? m.group( 1 ) : displayName;
+        String method = null;
+        int parent = displayName.lastIndexOf( '(' );
+        if ( parent != -1 )
+        {
+            method = displayName.substring( 0, parent );
+        }
+        return method;
     }
 }
diff --git a/surefire-api/src/test/java/org/apache/maven/plugin/surefire/runorder/ThreadedExecutionSchedulerTest.java b/surefire-api/src/test/java/org/apache/maven/plugin/surefire/runorder/ThreadedExecutionSchedulerTest.java
index 15963d7..6647504 100644
--- a/surefire-api/src/test/java/org/apache/maven/plugin/surefire/runorder/ThreadedExecutionSchedulerTest.java
+++ b/surefire-api/src/test/java/org/apache/maven/plugin/surefire/runorder/ThreadedExecutionSchedulerTest.java
@@ -21,6 +21,7 @@ package org.apache.maven.plugin.surefire.runorder;
 import java.util.List;
 
 import junit.framework.TestCase;
+import org.apache.maven.surefire.util.internal.ClassMethod;
 
 /**
  * @author Kristian Rosenvold
@@ -29,24 +30,23 @@ public class ThreadedExecutionSchedulerTest
     extends TestCase
 {
 
-    private final RunEntryStatistics a1 = RunEntryStatistics.fromValues( 200, 2, A.class, "at1" );
+    private final RunEntryStatistics a1 = fromValues( 200, 2, A.class, "at1" );
 
-    private final RunEntryStatistics a2 = RunEntryStatistics.fromValues( 300, 2, A.class, "at2" );
+    private final RunEntryStatistics a2 = fromValues( 300, 2, A.class, "at2" );
 
-    private final RunEntryStatistics b1 = RunEntryStatistics.fromValues( 400, 2, B.class, "bt1" );
+    private final RunEntryStatistics b1 = fromValues( 400, 2, B.class, "bt1" );
 
-    private final RunEntryStatistics b2 = RunEntryStatistics.fromValues( 300, 2, B.class, "bt2" );
+    private final RunEntryStatistics b2 = fromValues( 300, 2, B.class, "bt2" );
 
-    private final RunEntryStatistics c1 = RunEntryStatistics.fromValues( 400, 2, C.class, "ct1" );
+    private final RunEntryStatistics c1 = fromValues( 400, 2, C.class, "ct1" );
 
-    private final RunEntryStatistics c2 = RunEntryStatistics.fromValues( 200, 2, C.class, "ct2" );
+    private final RunEntryStatistics c2 = fromValues( 200, 2, C.class, "ct2" );
 
-    private final RunEntryStatistics d1 = RunEntryStatistics.fromValues( 401, 2, D.class, "ct2" );
+    private final RunEntryStatistics d1 = fromValues( 401, 2, D.class, "ct2" );
 
-    private final RunEntryStatistics e1 = RunEntryStatistics.fromValues( 200, 2, E.class, "ct2" );
+    private final RunEntryStatistics e1 = fromValues( 200, 2, E.class, "ct2" );
 
     public void testAddTest()
-        throws Exception
     {
         ThreadedExecutionScheduler threadedExecutionScheduler = new ThreadedExecutionScheduler( 2 );
         addPrioritizedTests( threadedExecutionScheduler );
@@ -57,17 +57,14 @@ public class ThreadedExecutionSchedulerTest
         assertEquals( D.class, result.get( 2 ) );
         assertEquals( A.class, result.get( 3 ) );
         assertEquals( E.class, result.get( 4 ) );
-
     }
 
     public void testAddTestJaggedResult()
-        throws Exception
     {
         ThreadedExecutionScheduler threadedExecutionScheduler = new ThreadedExecutionScheduler( 4 );
         addPrioritizedTests( threadedExecutionScheduler );
         final List result = threadedExecutionScheduler.getResult();
         assertEquals( 5, result.size() );
-
     }
 
     private void addPrioritizedTests( ThreadedExecutionScheduler threadedExecutionScheduler )
@@ -94,6 +91,11 @@ public class ThreadedExecutionSchedulerTest
         return priority;
     }
 
+    private static RunEntryStatistics fromValues( int runTime, int successfulBuilds, Class clazz, String testName )
+    {
+        ClassMethod classMethod = new ClassMethod( clazz.getName(), testName );
+        return new RunEntryStatistics( runTime, successfulBuilds, classMethod );
+    }
 
     class A
     {
diff --git a/surefire-its/pom.xml b/surefire-its/pom.xml
index 0cea53e..a90df17 100644
--- a/surefire-its/pom.xml
+++ b/surefire-its/pom.xml
@@ -183,7 +183,7 @@
                         <jdk.home>${jdk.home}</jdk.home>
                         <jacoco.agent>${jacoco-it.agent}</jacoco.agent>
                     </systemPropertyVariables>
-                    <redirectTestOutputToFile>false</redirectTestOutputToFile>
+                    <redirectTestOutputToFile>true</redirectTestOutputToFile>
                 </configuration>
                 <dependencies>
                     <dependency>
diff --git a/surefire-its/src/test/java/org/apache/maven/surefire/its/JUnit4RerunFailingTestsIT.java b/surefire-its/src/test/java/org/apache/maven/surefire/its/JUnit4RerunFailingTestsIT.java
index 7d6f560..b64edff 100644
--- a/surefire-its/src/test/java/org/apache/maven/surefire/its/JUnit4RerunFailingTestsIT.java
+++ b/surefire-its/src/test/java/org/apache/maven/surefire/its/JUnit4RerunFailingTestsIT.java
@@ -254,9 +254,9 @@ public class JUnit4RerunFailingTestsIT
     private void verifyFailuresNoRetry( OutputValidator outputValidator, int run, int failures, int errors, int flakes )
     {
         outputValidator.verifyTextInLog( "Failures:" );
-        outputValidator.verifyTextInLog( "testFailingTestOne(junit4.FlakyFirstTimeTest)" );
+        outputValidator.verifyTextInLog( "junit4.FlakyFirstTimeTest.testFailingTestOne" );
         outputValidator.verifyTextInLog( "ERROR" );
-        outputValidator.verifyTextInLog( "testErrorTestOne(junit4.FlakyFirstTimeTest)" );
+        outputValidator.verifyTextInLog( "junit4.FlakyFirstTimeTest.testErrorTestOne" );
 
         verifyStatistics( outputValidator, run, failures, errors, flakes );
     }
diff --git a/surefire-its/src/test/java/org/apache/maven/surefire/its/JUnitPlatformEnginesIT.java b/surefire-its/src/test/java/org/apache/maven/surefire/its/JUnitPlatformEnginesIT.java
index 332cbb9..ae04143 100644
--- a/surefire-its/src/test/java/org/apache/maven/surefire/its/JUnitPlatformEnginesIT.java
+++ b/surefire-its/src/test/java/org/apache/maven/surefire/its/JUnitPlatformEnginesIT.java
@@ -59,10 +59,10 @@ public class JUnitPlatformEnginesIT
     public static Iterable<Object[]> regexVersions()
     {
         ArrayList<Object[]> args = new ArrayList<Object[]>();
-        args.add( new Object[] { "1.0.0", "5.0.0", "1.0.0", "1.0.0" } );
+        args.add( new Object[] { "1.0.3", "5.0.3", "1.0.0", "1.0.0" } );
         args.add( new Object[] { "1.1.1", "5.1.1", "1.0.0", "1.0.0" } );
         args.add( new Object[] { "1.2.0", "5.2.0", "1.1.0", "1.0.0" } );
-        args.add( new Object[] { "1.3.1", "5.3.1", "1.1.1", "1.0.0" } );
+        args.add( new Object[] { "1.3.2", "5.3.2", "1.1.1", "1.0.0" } );
         args.add( new Object[] { "1.4.0-SNAPSHOT", "5.4.0-SNAPSHOT", "1.1.1", "1.0.0" } );
         return args;
     }
@@ -114,7 +114,7 @@ public class JUnitPlatformEnginesIT
                 + "  surefire-api-*.jar"
                 + "  surefire-logger-api-*.jar"
                 + "  common-java5-*.jar"
-                + "  junit-platform-launcher-1.3.1.jar";
+                + "  junit-platform-launcher-1.3.2.jar";
 
         lines = validator.loadLogLines( startsWith( "[DEBUG] provider(compact) classpath" ) );
 
@@ -138,7 +138,7 @@ public class JUnitPlatformEnginesIT
                 + "  opentest4j-" + opentest + ".jar"
                 + "  junit-jupiter-api-" + jupiter + ".jar"
                 + "  surefire-junit-platform-*.jar"
-                + "  junit-platform-launcher-1.3.1.jar";
+                + "  junit-platform-launcher-1.3.2.jar";
 
         lines = validator.loadLogLines( startsWith( "[DEBUG] boot(compact) classpath" ) );
 
diff --git a/surefire-its/src/test/java/org/apache/maven/surefire/its/jiras/Surefire1152RerunFailingTestsInSuiteIT.java b/surefire-its/src/test/java/org/apache/maven/surefire/its/jiras/Surefire1152RerunFailingTestsInSuiteIT.java
index 58e951a..ded2361 100644
--- a/surefire-its/src/test/java/org/apache/maven/surefire/its/jiras/Surefire1152RerunFailingTestsInSuiteIT.java
+++ b/surefire-its/src/test/java/org/apache/maven/surefire/its/jiras/Surefire1152RerunFailingTestsInSuiteIT.java
@@ -35,9 +35,9 @@ public class Surefire1152RerunFailingTestsInSuiteIT
     private static final String RUNNING_WITH_PROVIDER47 =
         "Using configured provider org.apache.maven.surefire.junitcore.JUnitCoreProvider";
 
-    public OutputValidator runMethodPattern( String projectName, String... goals )
+    private OutputValidator runMethodPattern( String... goals )
     {
-        SurefireLauncher launcher = unpack( projectName );
+        SurefireLauncher launcher = unpack("surefire-1152-rerunFailingTestsCount-suite" );
         for ( String goal : goals )
         {
             launcher.addGoal( goal );
@@ -51,13 +51,13 @@ public class Surefire1152RerunFailingTestsInSuiteIT
     @Test
     public void testJUnit48Provider4()
     {
-        runMethodPattern( "surefire-1152-rerunFailingTestsCount-suite", "-P surefire-junit4" );
+        runMethodPattern("-P surefire-junit4" );
     }
 
     @Test
     public void testJUnit48Provider47()
     {
-        runMethodPattern( "surefire-1152-rerunFailingTestsCount-suite", "-P surefire-junit47" )
+        runMethodPattern("-P surefire-junit47" )
             .verifyTextInLog( RUNNING_WITH_PROVIDER47 );
     }
 
diff --git a/surefire-its/src/test/java/org/apache/maven/surefire/its/jiras/Surefire1209RerunAndForkCountIT.java b/surefire-its/src/test/java/org/apache/maven/surefire/its/jiras/Surefire1209RerunAndForkCountIT.java
index 6ee87fb..1b5130f 100644
--- a/surefire-its/src/test/java/org/apache/maven/surefire/its/jiras/Surefire1209RerunAndForkCountIT.java
+++ b/surefire-its/src/test/java/org/apache/maven/surefire/its/jiras/Surefire1209RerunAndForkCountIT.java
@@ -22,8 +22,11 @@ package org.apache.maven.surefire.its.jiras;
 import org.apache.maven.it.VerificationException;
 import org.apache.maven.surefire.its.fixture.SurefireJUnit4IntegrationTestCase;
 import org.apache.maven.surefire.its.fixture.SurefireLauncher;
+import org.hamcrest.CoreMatchers;
 import org.junit.Test;
 
+import static org.hamcrest.CoreMatchers.*;
+
 /**
  * @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
  * @see <a href="https://issues.apache.org/jira/browse/SUREFIRE-1209">SUREFIRE-1209</a>
@@ -32,40 +35,39 @@ import org.junit.Test;
 public class Surefire1209RerunAndForkCountIT
         extends SurefireJUnit4IntegrationTestCase
 {
+    private static final String SUMMARY_COUNTS = "Tests run: 5, Failures: 0, Errors: 0, Skipped: 0, Flakes: 2";
+
     @Test
-    public void reusableForksJUnit47()
-            throws VerificationException
-    {
+    public void reusableForksJUnit47() throws VerificationException {
         unpack().executeTest()
-                .assertTestSuiteResults( 5, 0, 0, 0, 4 );
+                .assertTestSuiteResults( 5, 0, 0, 0, 4 )
+                .assertThatLogLine( containsString( SUMMARY_COUNTS ), is( 1 ) );
     }
 
     @Test
-    public void notReusableForksJUnit47()
-            throws VerificationException
-    {
+    public void notReusableForksJUnit47() throws VerificationException {
         unpack().reuseForks( false )
                 .executeTest()
-                .assertTestSuiteResults( 5, 0, 0, 0, 4 );
+                .assertTestSuiteResults( 5, 0, 0, 0, 4 )
+                .assertThatLogLine( containsString( SUMMARY_COUNTS ), is( 1 ) );
     }
 
     @Test
-    public void reusableForksJUnit4()
-            throws VerificationException
-    {
-        unpack().addGoal( "-Pjunit4" )
+    public void reusableForksJUnit4() throws VerificationException {
+        unpack().activateProfile( "junit4" )
                 .executeTest()
-                .assertTestSuiteResults( 5, 0, 0, 0, 4 );
+                .assertTestSuiteResults( 5, 0, 0, 0, 4 )
+                .assertThatLogLine( containsString( SUMMARY_COUNTS ), is( 1 ) );
     }
 
     @Test
     public void notReusableForksJUnit4()
-            throws VerificationException
-    {
-        unpack().addGoal( "-Pjunit4" )
+            throws VerificationException {
+        unpack().activateProfile( "junit4" )
                 .reuseForks( false )
                 .executeTest()
-                .assertTestSuiteResults( 5, 0, 0, 0, 4 );
+                .assertTestSuiteResults( 5, 0, 0, 0, 4 )
+                .assertThatLogLine( containsString( SUMMARY_COUNTS ), is( 1 ) );
     }
 
     private SurefireLauncher unpack()
diff --git a/surefire-its/src/test/java/org/apache/maven/surefire/its/jiras/Surefire943ReportContentIT.java b/surefire-its/src/test/java/org/apache/maven/surefire/its/jiras/Surefire943ReportContentIT.java
index 59d2170..0d3c4a3 100644
--- a/surefire-its/src/test/java/org/apache/maven/surefire/its/jiras/Surefire943ReportContentIT.java
+++ b/surefire-its/src/test/java/org/apache/maven/surefire/its/jiras/Surefire943ReportContentIT.java
@@ -74,7 +74,7 @@ public class Surefire943ReportContentIT
         Xpp3Dom child = children[0];
 
         Assert.assertEquals( className, child.getAttribute( "classname" ) );
-        Assert.assertEquals( className, child.getAttribute( "name" ) );
+        Assert.assertEquals( "", child.getAttribute( "name" ) );
 
         Assert.assertEquals( "Expected error tag for failed BeforeClass method for " + className, 1,
                              child.getChildren( "error" ).length );
@@ -84,7 +84,6 @@ public class Surefire943ReportContentIT
 
         Assert.assertTrue( "time for test failure in BeforeClass is expected to be resonably low",
                            Double.compare( Double.parseDouble( child.getAttribute( "time" ) ), 2.0d ) <= 0 );
-
     }
 
     private void validateSkipped( OutputValidator validator, String className )
@@ -97,7 +96,7 @@ public class Surefire943ReportContentIT
         Xpp3Dom child = children[0];
 
         Assert.assertEquals( className, child.getAttribute( "classname" ) );
-        Assert.assertEquals( className, child.getAttribute( "name" ) );
+        Assert.assertEquals( "", child.getAttribute( "name" ) );
 
         Assert.assertEquals( "Expected skipped tag for ignored method for " + className, 1,
                              child.getChildren( "skipped" ).length );
diff --git a/surefire-its/src/test/resources/fixture/testsuitexmlparser/TEST-org.apache.maven.surefire.test.SucceedingTest.xml b/surefire-its/src/test/resources/fixture/testsuitexmlparser/TEST-org.apache.maven.surefire.test.SucceedingTest.xml
deleted file mode 100644
index 2801bf6..0000000
--- a/surefire-its/src/test/resources/fixture/testsuitexmlparser/TEST-org.apache.maven.surefire.test.SucceedingTest.xml
+++ /dev/null
@@ -1,68 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<testsuite failures="0" time="0.008" errors="0" skipped="0" tests="2" name="org.apache.maven.surefire.test.SucceedingTest">
-  <properties>
-    <property name="surefire.version" value="2.13-SNAPSHOT"/>
-    <property name="java.runtime.name" value="Java(TM) SE Runtime Environment"/>
-    <property name="sun.boot.library.path" value="c:\java\jdk1.7.0_09\jre\bin"/>
-    <property name="java.vm.version" value="23.5-b02"/>
-    <property name="user.country.format" value="NO"/>
-    <property name="java.vm.vendor" value="Oracle Corporation"/>
-    <property name="java.vendor.url" value="http://java.oracle.com/"/>
-    <property name="path.separator" value=";"/>
-    <property name="guice.disable.misplaced.annotation.check" value="true"/>
-    <property name="java.vm.name" value="Java HotSpot(TM) 64-Bit Server VM"/>
-    <property name="file.encoding.pkg" value="sun.io"/>
-    <property name="user.script" value=""/>
-    <property name="user.country" value="US"/>
-    <property name="sun.java.launcher" value="SUN_STANDARD"/>
-    <property name="sun.os.patch.level" value="Service Pack 1"/>
-    <property name="java.vm.specification.name" value="Java Virtual Machine Specification"/>
-    <property name="user.dir" value="c:\workspace\maven-surefire\surefire-integration-tests\src\test\resources\surefire-803-multiFailsafeExec-failureInFirst"/>
-    <property name="java.runtime.version" value="1.7.0_09-b05"/>
-    <property name="java.awt.graphicsenv" value="sun.awt.Win32GraphicsEnvironment"/>
-    <property name="java.endorsed.dirs" value="c:\java\jdk1.7.0_09\jre\lib\endorsed"/>
-    <property name="os.arch" value="amd64"/>
-    <property name="java.io.tmpdir" value="C:\Users\krose\AppData\Local\Temp\"/>
-    <property name="line.separator" value="
-"/>
-    <property name="java.vm.specification.vendor" value="Oracle Corporation"/>
-    <property name="user.variant" value=""/>
-    <property name="os.name" value="Windows 7"/>
-    <property name="classworlds.conf" value="c:/java/apache-maven-3.0.4/bin/m2.conf"/>
-    <property name="sun.jnu.encoding" value="Cp1252"/>
-    <property name="java.library.path" value="c:\java\jdk1.7.0_09\bin;C:\Windows\Sun\Java\bin;C:\Windows\system32;C:\Windows;x:\bin;.;C:\java\Git\local\bin;C:\java\Git\mingw\bin;C:\java\Git\bin;c:\java\jdk1.7.0_09\bin;c:\java\Subversion;c:\Program Files\Common Files\Microsoft Shared\Microsoft Online Services;c:\Program Files (x86)\Common Files\Microsoft Shared\Microsoft Online Services;c:\Windows\system32;c:\Windows;c:\Windows\System32\Wbem;c:\Windows\System32\WindowsPowerShell\v1.0\;c:\ [...]
-    <property name="java.specification.name" value="Java Platform API Specification"/>
-    <property name="java.class.version" value="51.0"/>
-    <property name="sun.management.compiler" value="HotSpot 64-Bit Tiered Compilers"/>
-    <property name="os.version" value="6.1"/>
-    <property name="user.home" value="C:\Users\krose"/>
-    <property name="user.timezone" value="Europe/Paris"/>
-    <property name="java.awt.printerjob" value="sun.awt.windows.WPrinterJob"/>
-    <property name="java.specification.version" value="1.7"/>
-    <property name="file.encoding" value="Cp1252"/>
-    <property name="user.name" value="krose"/>
-    <property name="java.class.path" value="c:/java/apache-maven-3.0.4/boot/plexus-classworlds-2.4.jar"/>
-    <property name="java.vm.specification.version" value="1.7"/>
-    <property name="sun.arch.data.model" value="64"/>
-    <property name="java.home" value="c:\java\jdk1.7.0_09\jre"/>
-    <property name="sun.java.command" value="org.codehaus.plexus.classworlds.launcher.Launcher -Dsurefire.version=2.13-SNAPSHOT clean verify"/>
-    <property name="java.specification.vendor" value="Oracle Corporation"/>
-    <property name="user.language" value="en"/>
-    <property name="user.language.format" value="no"/>
-    <property name="awt.toolkit" value="sun.awt.windows.WToolkit"/>
-    <property name="java.vm.info" value="mixed mode"/>
-    <property name="java.version" value="1.7.0_09"/>
-    <property name="java.ext.dirs" value="c:\java\jdk1.7.0_09\jre\lib\ext;C:\Windows\Sun\Java\lib\ext"/>
-    <property name="sun.boot.class.path" value="c:\java\jdk1.7.0_09\jre\lib\resources.jar;c:\java\jdk1.7.0_09\jre\lib\rt.jar;c:\java\jdk1.7.0_09\jre\lib\sunrsasign.jar;c:\java\jdk1.7.0_09\jre\lib\jsse.jar;c:\java\jdk1.7.0_09\jre\lib\jce.jar;c:\java\jdk1.7.0_09\jre\lib\charsets.jar;c:\java\jdk1.7.0_09\jre\lib\jfr.jar;c:\java\jdk1.7.0_09\jre\classes"/>
-    <property name="java.vendor" value="Oracle Corporation"/>
-    <property name="maven.home" value="c:\java\apache-maven-3.0.4"/>
-    <property name="file.separator" value="\"/>
-    <property name="java.vendor.url.bug" value="http://bugreport.sun.com/bugreport/"/>
-    <property name="sun.cpu.endian" value="little"/>
-    <property name="sun.io.unicode.encoding" value="UnicodeLittle"/>
-    <property name="sun.desktop" value="windows"/>
-    <property name="sun.cpu.isalist" value="amd64"/>
-  </properties>
-  <testcase time="0.007" classname="org.apache.maven.surefire.test.SucceedingTest" name="defaultTestValueIs_Value"/>
-  <testcase time="0.001" classname="org.apache.maven.surefire.test.SucceedingTest" name="setTestAndRetrieveValue"/>
-</testsuite>
\ No newline at end of file
diff --git a/surefire-its/src/test/resources/fixture/testsuitexmlparser/org.apache.maven.surefire.test.FailingTest.txt b/surefire-its/src/test/resources/fixture/testsuitexmlparser/org.apache.maven.surefire.test.FailingTest.txt
deleted file mode 100644
index 38abc1f..0000000
--- a/surefire-its/src/test/resources/fixture/testsuitexmlparser/org.apache.maven.surefire.test.FailingTest.txt
+++ /dev/null
@@ -1,84 +0,0 @@
--------------------------------------------------------------------------------
-Test set: org.apache.maven.surefire.test.FailingTest
--------------------------------------------------------------------------------
-Tests run: 2, Failures: 2, Errors: 0, Skipped: 0, Time elapsed: 0.046 sec <<< FAILURE!
-defaultTestValueIs_Value(org.apache.maven.surefire.test.FailingTest)  Time elapsed: 0.013 sec  <<< FAILURE!
-java.lang.AssertionError: 
-Expected: "wrong"
-     got: "value"
-
-	at org.junit.Assert.assertThat(Assert.java:778)
-	at org.junit.Assert.assertThat(Assert.java:736)
-	at org.apache.maven.surefire.test.FailingTest.defaultTestValueIs_Value(FailingTest.java:23)
-	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
-	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
-	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
-	at java.lang.reflect.Method.invoke(Method.java:601)
-	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
-	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
-	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
-	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
-	at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:31)
-	at org.junit.rules.TestWatchman$1.evaluate(TestWatchman.java:48)
-	at org.junit.runners.BlockJUnit4ClassRunner.runNotIgnored(BlockJUnit4ClassRunner.java:79)
-	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:71)
-	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:49)
-	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
-	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
-	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
-	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
-	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
-	at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
-	at org.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:262)
-	at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:151)
-	at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:122)
-	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
-	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
-	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
-	at java.lang.reflect.Method.invoke(Method.java:601)
-	at org.apache.maven.surefire.util.ReflectionUtils.invokeMethodWithArray(ReflectionUtils.java:189)
-	at org.apache.maven.surefire.booter.ProviderFactory$ProviderProxy.invoke(ProviderFactory.java:165)
-	at org.apache.maven.surefire.booter.ProviderFactory.invokeProvider(ProviderFactory.java:85)
-	at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:128)
-	at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:88)
-
-setTestAndRetrieveValue(org.apache.maven.surefire.test.FailingTest)  Time elapsed: 0.001 sec  <<< FAILURE!
-java.lang.AssertionError: 
-Expected: "bar"
-     got: "foo"
-
-	at org.junit.Assert.assertThat(Assert.java:778)
-	at org.junit.Assert.assertThat(Assert.java:736)
-	at org.apache.maven.surefire.test.FailingTest.setTestAndRetrieveValue(FailingTest.java:34)
-	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
-	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
-	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
-	at java.lang.reflect.Method.invoke(Method.java:601)
-	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
-	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
-	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
-	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
-	at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:31)
-	at org.junit.rules.TestWatchman$1.evaluate(TestWatchman.java:48)
-	at org.junit.runners.BlockJUnit4ClassRunner.runNotIgnored(BlockJUnit4ClassRunner.java:79)
-	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:71)
-	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:49)
-	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
-	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
-	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
-	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
-	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
-	at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
-	at org.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:262)
-	at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:151)
-	at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:122)
-	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
-	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
-	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
-	at java.lang.reflect.Method.invoke(Method.java:601)
-	at org.apache.maven.surefire.util.ReflectionUtils.invokeMethodWithArray(ReflectionUtils.java:189)
-	at org.apache.maven.surefire.booter.ProviderFactory$ProviderProxy.invoke(ProviderFactory.java:165)
-	at org.apache.maven.surefire.booter.ProviderFactory.invokeProvider(ProviderFactory.java:85)
-	at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:128)
-	at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:88)
-
diff --git a/surefire-its/src/test/resources/fixture/testsuitexmlparser/org.apache.maven.surefire.test.SucceedingTest.txt b/surefire-its/src/test/resources/fixture/testsuitexmlparser/org.apache.maven.surefire.test.SucceedingTest.txt
deleted file mode 100644
index 9433827..0000000
--- a/surefire-its/src/test/resources/fixture/testsuitexmlparser/org.apache.maven.surefire.test.SucceedingTest.txt
+++ /dev/null
@@ -1,4 +0,0 @@
--------------------------------------------------------------------------------
-Test set: org.apache.maven.surefire.test.SucceedingTest
--------------------------------------------------------------------------------
-Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.044 sec
diff --git a/surefire-its/src/test/resources/surefire-570-multipleReportDirectories/module1/src/test/resources/surefire-reports/TEST-org.apache.maven.surefireReport.surefireReportTest.MyClassTest.xml b/surefire-its/src/test/resources/surefire-570-multipleReportDirectories/module1/src/test/resources/surefire-reports2/TEST-org.apache.maven.surefireReport.surefireReportTest.MyClassTest.xml
similarity index 100%
rename from surefire-its/src/test/resources/surefire-570-multipleReportDirectories/module1/src/test/resources/surefire-reports/TEST-org.apache.maven.surefireReport.surefireReportTest.MyClassTest.xml
rename to surefire-its/src/test/resources/surefire-570-multipleReportDirectories/module1/src/test/resources/surefire-reports2/TEST-org.apache.maven.surefireReport.surefireReportTest.MyClassTest.xml
diff --git a/surefire-its/src/test/resources/surefire-570-multipleReportDirectories/module1/src/test/resources/surefire-reports/org.apache.maven.surefireReport.surefireReportTest.MyClassTest.txt b/surefire-its/src/test/resources/surefire-570-multipleReportDirectories/module1/src/test/resources/surefire-reports2/org.apache.maven.surefireReport.surefireReportTest.MyClassTest.txt
similarity index 86%
rename from surefire-its/src/test/resources/surefire-570-multipleReportDirectories/module1/src/test/resources/surefire-reports/org.apache.maven.surefireReport.surefireReportTest.MyClassTest.txt
rename to surefire-its/src/test/resources/surefire-570-multipleReportDirectories/module1/src/test/resources/surefire-reports2/org.apache.maven.surefireReport.surefireReportTest.MyClassTest.txt
index 9964f13..7a2f989 100644
--- a/surefire-its/src/test/resources/surefire-570-multipleReportDirectories/module1/src/test/resources/surefire-reports/org.apache.maven.surefireReport.surefireReportTest.MyClassTest.txt
+++ b/surefire-its/src/test/resources/surefire-570-multipleReportDirectories/module1/src/test/resources/surefire-reports2/org.apache.maven.surefireReport.surefireReportTest.MyClassTest.txt
@@ -2,7 +2,7 @@
 Test set: org.apache.maven.surefireReport.surefireReportTest.module1.MyDummyClassTest
 -------------------------------------------------------------------------------
 Tests run: 2, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 0.049 sec <<< FAILURE!
-testGetFooKO(org.apache.maven.surefireReport.surefireReportTest.module1.MyDummyClassTest)  Time elapsed: 0.01 sec  <<< FAILURE!
+org.apache.maven.surefireReport.surefireReportTest.module1.MyDummyClassTest.testGetFooKO  Time elapsed: 0.01 sec  <<< FAILURE!
 junit.framework.AssertionFailedError: expected:<18> but was:<42>
 	at junit.framework.Assert.fail(Assert.java:47)
 	at junit.framework.Assert.failNotEquals(Assert.java:280)
diff --git a/surefire-its/src/test/resources/surefire-570-multipleReportDirectories/module2/src/test/resources/surefire-reports/TEST-org.apache.maven.surefireReport.surefireReportTest.MyClassTest.xml b/surefire-its/src/test/resources/surefire-570-multipleReportDirectories/module2/src/test/resources/surefire-reports2/TEST-org.apache.maven.surefireReport.surefireReportTest.MyClassTest.xml
similarity index 97%
rename from surefire-its/src/test/resources/surefire-570-multipleReportDirectories/module2/src/test/resources/surefire-reports/TEST-org.apache.maven.surefireReport.surefireReportTest.MyClassTest.xml
rename to surefire-its/src/test/resources/surefire-570-multipleReportDirectories/module2/src/test/resources/surefire-reports2/TEST-org.apache.maven.surefireReport.surefireReportTest.MyClassTest.xml
index 2c9cbed..d90475a 100644
--- a/surefire-its/src/test/resources/surefire-570-multipleReportDirectories/module2/src/test/resources/surefire-reports/TEST-org.apache.maven.surefireReport.surefireReportTest.MyClassTest.xml
+++ b/surefire-its/src/test/resources/surefire-570-multipleReportDirectories/module2/src/test/resources/surefire-reports2/TEST-org.apache.maven.surefireReport.surefireReportTest.MyClassTest.xml
@@ -57,7 +57,7 @@
     <property name="sun.desktop" value="gnome"/>
     <property name="sun.cpu.isalist" value=""/>
   </properties>
-  <testcase time="0.005" classname="org.apache.maven.surefireReport.surefireReportTest.module1.MyDummyClassM2Test" name="testGetFooKO">
+  <testcase time="0.005" classname="org.apache.maven.surefireReport.surefireReportTest.module2.MyDummyClassM2Test" name="testGetFooKO">
     <failure message="expected:&lt;18&gt; but was:&lt;42&gt;" type="junit.framework.AssertionFailedError">junit.framework.AssertionFailedError: expected:&lt;18&gt; but was:&lt;42&gt;
 	at junit.framework.Assert.fail(Assert.java:47)
 	at junit.framework.Assert.failNotEquals(Assert.java:280)
@@ -67,5 +67,5 @@
 	at org.apache.maven.surefireReport.surefireReportTest.module1.MyDummyClassTest.testGetFooKO(MyClassTest.java:10)
 </failure>
   </testcase>
-  <testcase time="0" classname="org.apache.maven.surefireReport.surefireReportTest.module1.MyDummyClassM2Test" name="testGetFooOK"/>
+  <testcase time="0" classname="org.apache.maven.surefireReport.surefireReportTest.module2.MyDummyClassM2Test" name="testGetFooOK"/>
 </testsuite>
diff --git a/surefire-its/src/test/resources/surefire-570-multipleReportDirectories/module2/src/test/resources/surefire-reports/org.apache.maven.surefireReport.surefireReportTest.MyClassTest.txt b/surefire-its/src/test/resources/surefire-570-multipleReportDirectories/module2/src/test/resources/surefire-reports2/org.apache.maven.surefireReport.surefireReportTest.MyClassTest.txt
similarity index 86%
rename from surefire-its/src/test/resources/surefire-570-multipleReportDirectories/module2/src/test/resources/surefire-reports/org.apache.maven.surefireReport.surefireReportTest.MyClassTest.txt
rename to surefire-its/src/test/resources/surefire-570-multipleReportDirectories/module2/src/test/resources/surefire-reports2/org.apache.maven.surefireReport.surefireReportTest.MyClassTest.txt
index 9964f13..7a2f989 100644
--- a/surefire-its/src/test/resources/surefire-570-multipleReportDirectories/module2/src/test/resources/surefire-reports/org.apache.maven.surefireReport.surefireReportTest.MyClassTest.txt
+++ b/surefire-its/src/test/resources/surefire-570-multipleReportDirectories/module2/src/test/resources/surefire-reports2/org.apache.maven.surefireReport.surefireReportTest.MyClassTest.txt
@@ -2,7 +2,7 @@
 Test set: org.apache.maven.surefireReport.surefireReportTest.module1.MyDummyClassTest
 -------------------------------------------------------------------------------
 Tests run: 2, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 0.049 sec <<< FAILURE!
-testGetFooKO(org.apache.maven.surefireReport.surefireReportTest.module1.MyDummyClassTest)  Time elapsed: 0.01 sec  <<< FAILURE!
+org.apache.maven.surefireReport.surefireReportTest.module1.MyDummyClassTest.testGetFooKO  Time elapsed: 0.01 sec  <<< FAILURE!
 junit.framework.AssertionFailedError: expected:<18> but was:<42>
 	at junit.framework.Assert.fail(Assert.java:47)
 	at junit.framework.Assert.failNotEquals(Assert.java:280)
diff --git a/surefire-its/src/test/resources/surefire-570-multipleReportDirectories/pom.xml b/surefire-its/src/test/resources/surefire-570-multipleReportDirectories/pom.xml
index b3238ea..ba51625 100644
--- a/surefire-its/src/test/resources/surefire-570-multipleReportDirectories/pom.xml
+++ b/surefire-its/src/test/resources/surefire-570-multipleReportDirectories/pom.xml
@@ -45,7 +45,7 @@
               <configuration>
                 <reportsDirectories>
                   <reportsDirectory>${basedir}/target/surefire-reports</reportsDirectory>
-                  <reportsDirectory>${basedir}/src/test/resources/surefire-reports</reportsDirectory>
+                  <reportsDirectory>${basedir}/src/test/resources/surefire-reports2</reportsDirectory>
                 </reportsDirectories>
               </configuration>
             </plugin>
@@ -96,7 +96,7 @@
         <configuration>
           <reportsDirectories>
             <reportsDirectory>${basedir}/target/surefire-reports</reportsDirectory>
-            <reportsDirectory>${basedir}/src/test/resources/surefire-reports</reportsDirectory>
+            <reportsDirectory>${basedir}/src/test/resources/surefire-reports2</reportsDirectory>
           </reportsDirectories>
         </configuration>
         <reportSets>
diff --git a/surefire-providers/common-java5/src/main/java/org/apache/maven/surefire/report/PojoStackTraceWriter.java b/surefire-providers/common-java5/src/main/java/org/apache/maven/surefire/report/PojoStackTraceWriter.java
index 626392b..2f369e8 100644
--- a/surefire-providers/common-java5/src/main/java/org/apache/maven/surefire/report/PojoStackTraceWriter.java
+++ b/surefire-providers/common-java5/src/main/java/org/apache/maven/surefire/report/PojoStackTraceWriter.java
@@ -24,6 +24,7 @@ import org.apache.maven.surefire.util.internal.StringUtils;
 
 import java.io.PrintWriter;
 import java.io.StringWriter;
+import java.util.Objects;
 
 /**
  * Write the trace out for a POJO test.
@@ -109,4 +110,27 @@ public class PojoStackTraceWriter
         }
         return false;
     }
+
+    @Override
+    public boolean equals( Object o )
+    {
+        if ( this == o )
+        {
+            return true;
+        }
+        if ( o == null || getClass() != o.getClass() )
+        {
+            return false;
+        }
+        PojoStackTraceWriter that = ( PojoStackTraceWriter ) o;
+        return Objects.equals( t, that.t )
+                && Objects.equals( testClass, that.testClass )
+                && Objects.equals( testMethod, that.testMethod );
+    }
+
+    @Override
+    public int hashCode()
+    {
+        return Objects.hash( t, testClass, testMethod );
+    }
 }
diff --git a/surefire-providers/common-junit4/src/main/java/org/apache/maven/surefire/common/junit4/JUnit4ProviderUtil.java b/surefire-providers/common-junit4/src/main/java/org/apache/maven/surefire/common/junit4/JUnit4ProviderUtil.java
index d19a0e1..702ee7f 100644
--- a/surefire-providers/common-junit4/src/main/java/org/apache/maven/surefire/common/junit4/JUnit4ProviderUtil.java
+++ b/surefire-providers/common-junit4/src/main/java/org/apache/maven/surefire/common/junit4/JUnit4ProviderUtil.java
@@ -20,14 +20,17 @@ package org.apache.maven.surefire.common.junit4;
  */
 
 import java.util.HashSet;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Set;
 
+import org.apache.maven.surefire.util.internal.ClassMethod;
 import org.junit.runner.Description;
 import org.junit.runner.manipulation.Filter;
 import org.junit.runner.notification.Failure;
 
-import static org.apache.maven.surefire.util.internal.StringUtils.isBlank;
+import static org.apache.maven.surefire.util.internal.TestClassMethodNameUtils.extractClassName;
+import static org.apache.maven.surefire.util.internal.TestClassMethodNameUtils.extractMethodName;
 import static org.junit.runner.Description.TEST_MECHANISM;
 
 /**
@@ -75,33 +78,30 @@ public final class JUnit4ProviderUtil
      * @param description method(class) or method[#](class) or method[#whatever-literals](class)
      * @return method JUnit test method
      */
-    public static ClassMethod cutTestClassAndMethod( Description description )
+    public static ClassMethod toClassMethod( Description description )
     {
-        String name = description.getDisplayName();
-        String clazz = null;
-        String method = null;
-        if ( name != null )
+        String clazz = extractClassName( description.getDisplayName() );
+        if ( clazz == null || isInsaneJunitNullString( clazz ) )
         {
-            // The order is : 1.method and then 2.class
-            // method(class)
-            name = name.trim();
-            if ( name.endsWith( ")" ) )
+            // This can happen upon early failures (class instantiation error etc)
+            Iterator<Description> it = description.getChildren().iterator();
+            if ( it.hasNext() )
             {
-                int classBracket = name.lastIndexOf( '(' );
-                if ( classBracket != -1 )
-                {
-                    clazz = tryBlank( name.substring( classBracket + 1, name.length() - 1 ) );
-                    method = tryBlank( name.substring( 0, classBracket ) );
-                }
+                description = it.next();
+                clazz = extractClassName( description.getDisplayName() );
+            }
+            if ( clazz == null )
+            {
+                clazz = "Test Instantiation Error";
             }
         }
+        String method = extractMethodName( description.getDisplayName() );
         return new ClassMethod( clazz, method );
     }
 
-    private static String tryBlank( String s )
+    private static boolean isInsaneJunitNullString( String value )
     {
-        s = s.trim();
-        return isBlank( s ) ? null : s;
+        return "null".equals( value );
     }
 
     public static Filter createMatchAnyDescriptionFilter( Iterable<Description> descriptions )
diff --git a/surefire-providers/common-junit4/src/main/java/org/apache/maven/surefire/common/junit4/JUnit4Reflector.java b/surefire-providers/common-junit4/src/main/java/org/apache/maven/surefire/common/junit4/JUnit4Reflector.java
index bbdeabb..9efe425 100644
--- a/surefire-providers/common-junit4/src/main/java/org/apache/maven/surefire/common/junit4/JUnit4Reflector.java
+++ b/surefire-providers/common-junit4/src/main/java/org/apache/maven/surefire/common/junit4/JUnit4Reflector.java
@@ -117,7 +117,7 @@ public final class JUnit4Reflector
         @Override
         public boolean equals( Object obj )
         {
-            return obj instanceof Annotation && obj instanceof Ignore && equalValue( ( Ignore ) obj );
+            return obj instanceof Ignore && equalValue( ( Ignore ) obj );
         }
 
         @Override
diff --git a/surefire-providers/common-junit4/src/main/java/org/apache/maven/surefire/common/junit4/JUnit4RunListener.java b/surefire-providers/common-junit4/src/main/java/org/apache/maven/surefire/common/junit4/JUnit4RunListener.java
index 7ed2ad9..648f910 100644
--- a/surefire-providers/common-junit4/src/main/java/org/apache/maven/surefire/common/junit4/JUnit4RunListener.java
+++ b/surefire-providers/common-junit4/src/main/java/org/apache/maven/surefire/common/junit4/JUnit4RunListener.java
@@ -24,17 +24,17 @@ import org.apache.maven.surefire.report.RunListener;
 import org.apache.maven.surefire.report.SimpleReportEntry;
 import org.apache.maven.surefire.report.StackTraceWriter;
 import org.apache.maven.surefire.testset.TestSetFailedException;
+import org.apache.maven.surefire.util.internal.ClassMethod;
 import org.junit.runner.Description;
 import org.junit.runner.Result;
 import org.junit.runner.notification.Failure;
 
 import static org.apache.maven.surefire.common.junit4.JUnit4ProviderUtil.isFailureInsideJUnitItself;
+import static org.apache.maven.surefire.common.junit4.JUnit4ProviderUtil.toClassMethod;
 import static org.apache.maven.surefire.common.junit4.JUnit4Reflector.getAnnotatedIgnoreValue;
 import static org.apache.maven.surefire.report.SimpleReportEntry.assumption;
 import static org.apache.maven.surefire.report.SimpleReportEntry.ignored;
 import static org.apache.maven.surefire.report.SimpleReportEntry.withException;
-import static org.apache.maven.surefire.util.internal.TestClassMethodNameUtils.extractClassName;
-import static org.apache.maven.surefire.util.internal.TestClassMethodNameUtils.extractMethodName;
 
 /**
  * RunListener for JUnit4, delegates to our own RunListener
@@ -74,7 +74,8 @@ public class JUnit4RunListener
         throws Exception
     {
         String reason = getAnnotatedIgnoreValue( description );
-        reporter.testSkipped( ignored( getClassName( description ), description.getDisplayName(), reason ) );
+        ClassMethod classMethod = toClassMethod( description );
+        reporter.testSkipped( ignored( classMethod.getClazz(), classMethod.getMethod(), reason ) );
     }
 
     /**
@@ -108,16 +109,9 @@ public class JUnit4RunListener
     {
         try
         {
-            String testHeader = failure.getTestHeader();
-            if ( isInsaneJunitNullString( testHeader ) )
-            {
-                testHeader = "Failure when constructing test";
-            }
-
-            String testClassName = getClassName( failure.getDescription() );
             StackTraceWriter stackTrace = createStackTraceWriter( failure );
-
-            ReportEntry report = withException( testClassName, testHeader, stackTrace );
+            ClassMethod classMethod = toClassMethod( failure.getDescription() );
+            ReportEntry report = withException( classMethod.getClazz(), classMethod.getMethod(), stackTrace );
 
             if ( failure.getException() instanceof AssertionError )
             {
@@ -140,8 +134,9 @@ public class JUnit4RunListener
         try
         {
             Description desc = failure.getDescription();
-            String test = getClassName( desc );
-            reporter.testAssumptionFailure( assumption( test, desc.getDisplayName(), failure.getMessage() ) );
+            ClassMethod classMethod = toClassMethod( desc );
+            ReportEntry report = assumption( classMethod.getClazz(), classMethod.getMethod(), failure.getMessage() );
+            reporter.testAssumptionFailure( report );
         }
         finally
         {
@@ -173,25 +168,6 @@ public class JUnit4RunListener
         reporter.testExecutionSkippedByUser();
     }
 
-    private String getClassName( Description description )
-    {
-        String name = extractDescriptionClassName( description );
-        if ( name == null || isInsaneJunitNullString( name ) )
-        {
-            // This can happen upon early failures (class instantiation error etc)
-            Description subDescription = description.getChildren().get( 0 );
-            if ( subDescription != null )
-            {
-                name = extractDescriptionClassName( subDescription );
-            }
-            if ( name == null )
-            {
-                name = "Test Instantiation Error";
-            }
-        }
-        return name;
-    }
-
     protected StackTraceWriter createStackTraceWriter( Failure failure )
     {
         return new JUnit4StackTraceWriter( failure );
@@ -199,17 +175,8 @@ public class JUnit4RunListener
 
     protected SimpleReportEntry createReportEntry( Description description )
     {
-        return new SimpleReportEntry( getClassName( description ), description.getDisplayName() );
-    }
-
-    protected String extractDescriptionClassName( Description description )
-    {
-        return extractClassName( description.getDisplayName() );
-    }
-
-    protected String extractDescriptionMethodName( Description description )
-    {
-        return extractMethodName( description.getDisplayName() );
+        ClassMethod classMethod = toClassMethod( description );
+        return new SimpleReportEntry( classMethod.getClazz(), classMethod.getMethod() );
     }
 
     public static void rethrowAnyTestMechanismFailures( Result run )
diff --git a/surefire-providers/common-junit4/src/main/java/org/apache/maven/surefire/common/junit4/JUnit4StackTraceWriter.java b/surefire-providers/common-junit4/src/main/java/org/apache/maven/surefire/common/junit4/JUnit4StackTraceWriter.java
index 78cefb6..f60a30d 100644
--- a/surefire-providers/common-junit4/src/main/java/org/apache/maven/surefire/common/junit4/JUnit4StackTraceWriter.java
+++ b/surefire-providers/common-junit4/src/main/java/org/apache/maven/surefire/common/junit4/JUnit4StackTraceWriter.java
@@ -22,10 +22,10 @@ package org.apache.maven.surefire.common.junit4;
 import org.apache.maven.surefire.report.SafeThrowable;
 import org.apache.maven.surefire.report.SmartStackTraceParser;
 import org.apache.maven.surefire.report.StackTraceWriter;
+import org.apache.maven.surefire.util.internal.ClassMethod;
 import org.junit.runner.notification.Failure;
 
-import static org.apache.maven.surefire.util.internal.TestClassMethodNameUtils.extractClassName;
-import static org.apache.maven.surefire.util.internal.TestClassMethodNameUtils.extractMethodName;
+import static org.apache.maven.surefire.common.junit4.JUnit4ProviderUtil.toClassMethod;
 import static org.apache.maven.surefire.report.SmartStackTraceParser.stackTraceWithFocusOnClassAsString;
 
 /**
@@ -37,8 +37,7 @@ import static org.apache.maven.surefire.report.SmartStackTraceParser.stackTraceW
 public class JUnit4StackTraceWriter
     implements StackTraceWriter
 {
-    // Member Variables
-    protected final Failure junitFailure;
+    private final Failure junitFailure;
 
     /**
      * Constructor.
@@ -78,24 +77,14 @@ public class JUnit4StackTraceWriter
         return "";
     }
 
-    protected String getTestClassName()
-    {
-        return extractClassName( junitFailure.getDescription().getDisplayName() );
-    }
-
-    protected String getTestMethodName()
-    {
-        return extractMethodName( junitFailure.getDescription().getDisplayName() );
-    }
-
     @Override
-    @SuppressWarnings( "ThrowableResultOfMethodCallIgnored" )
     public String smartTrimmedStackTrace()
     {
         Throwable exception = junitFailure.getException();
+        ClassMethod classMethod = toClassMethod( junitFailure.getDescription() );
         return exception == null
             ? junitFailure.getMessage()
-            : new SmartStackTraceParser( getTestClassName(), exception, getTestMethodName() ).getString();
+            : new SmartStackTraceParser( classMethod.getClazz(), exception, classMethod.getMethod() ).getString();
     }
 
     /**
@@ -106,7 +95,7 @@ public class JUnit4StackTraceWriter
     @Override
     public String writeTrimmedTraceToString()
     {
-        String testClass = getTestClassName();
+        String testClass = toClassMethod( junitFailure.getDescription() ).getClazz();
         try
         {
             Throwable e = junitFailure.getException();
diff --git a/surefire-providers/common-junit4/src/main/java/org/apache/maven/surefire/common/junit4/Notifier.java b/surefire-providers/common-junit4/src/main/java/org/apache/maven/surefire/common/junit4/Notifier.java
index c2c6df8..de0ddc4 100644
--- a/surefire-providers/common-junit4/src/main/java/org/apache/maven/surefire/common/junit4/Notifier.java
+++ b/surefire-providers/common-junit4/src/main/java/org/apache/maven/surefire/common/junit4/Notifier.java
@@ -32,7 +32,7 @@ import java.util.Queue;
 import java.util.concurrent.ConcurrentLinkedQueue;
 import java.util.concurrent.atomic.AtomicInteger;
 
-import static org.apache.maven.surefire.common.junit4.JUnit4ProviderUtil.cutTestClassAndMethod;
+import static org.apache.maven.surefire.common.junit4.JUnit4ProviderUtil.toClassMethod;
 import static org.apache.maven.surefire.util.internal.ConcurrencyUtils.countDownToZero;
 
 /**
@@ -100,7 +100,7 @@ public class Notifier
         super.fireTestStarted( description );
         if ( !testClassNames.isEmpty() )
         {
-            testClassNames.remove( cutTestClassAndMethod( description ).getClazz() );
+            testClassNames.remove( toClassMethod( description ).getClazz() );
         }
     }
 
diff --git a/surefire-providers/common-junit4/src/test/java/org/apache/maven/surefire/common/junit4/JUnit4ProviderUtilTest.java b/surefire-providers/common-junit4/src/test/java/org/apache/maven/surefire/common/junit4/JUnit4ProviderUtilTest.java
index 163308c..15adc32 100644
--- a/surefire-providers/common-junit4/src/test/java/org/apache/maven/surefire/common/junit4/JUnit4ProviderUtilTest.java
+++ b/surefire-providers/common-junit4/src/test/java/org/apache/maven/surefire/common/junit4/JUnit4ProviderUtilTest.java
@@ -20,6 +20,7 @@ package org.apache.maven.surefire.common.junit4;
  */
 
 import junit.framework.TestCase;
+import org.apache.maven.surefire.util.internal.ClassMethod;
 import org.junit.runner.Description;
 import org.junit.runner.notification.Failure;
 
@@ -64,25 +65,25 @@ public class JUnit4ProviderUtilTest
     public void testIllegalTestDescription$NegativeTest()
     {
         Description test = Description.createSuiteDescription( "someTestMethod" );
-        ClassMethod classMethod = cutTestClassAndMethod( test );
-        assertFalse( classMethod.isValid() );
+        ClassMethod classMethod = JUnit4ProviderUtil.toClassMethod( test );
+        assertFalse( classMethod.isValidTest() );
     }
 
     public void testOldJUnitParameterizedDescriptionParser()
     {
         Description test = Description.createTestDescription( T1.class, " \n testMethod[5] " );
         assertEquals( " \n testMethod[5] (" + T1.class.getName() + ")", test.getDisplayName() );
-        ClassMethod classMethod = cutTestClassAndMethod( test );
-        assertTrue( classMethod.isValid() );
-        assertEquals( "testMethod[5]", classMethod.getMethod() );
+        ClassMethod classMethod = JUnit4ProviderUtil.toClassMethod( test );
+        assertTrue( classMethod.isValidTest() );
+        assertEquals( " \n testMethod[5] ", classMethod.getMethod() );
         assertEquals( T1.class.getName(), classMethod.getClazz() );
     }
 
     public void testNewJUnitParameterizedDescriptionParser()
     {
         Description test = Description.createTestDescription( T1.class, "flakyTest[3: (Test11); Test12; Test13;]" );
-        ClassMethod classMethod = cutTestClassAndMethod( test );
-        assertTrue( classMethod.isValid() );
+        ClassMethod classMethod = JUnit4ProviderUtil.toClassMethod( test );
+        assertTrue( classMethod.isValidTest() );
         assertEquals( "flakyTest[3: (Test11); Test12; Test13;]", classMethod.getMethod() );
         assertEquals( T1.class.getName(), classMethod.getClazz() );
     }
diff --git a/surefire-providers/common-junit48/src/main/java/org/apache/maven/surefire/common/junit48/JUnit46StackTraceWriter.java b/surefire-providers/common-junit48/src/main/java/org/apache/maven/surefire/common/junit48/JUnit46StackTraceWriter.java
deleted file mode 100644
index 4051e19..0000000
--- a/surefire-providers/common-junit48/src/main/java/org/apache/maven/surefire/common/junit48/JUnit46StackTraceWriter.java
+++ /dev/null
@@ -1,60 +0,0 @@
-package org.apache.maven.surefire.common.junit48;
-
-/*
- * 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.surefire.common.junit4.JUnit4StackTraceWriter;
-import org.junit.runner.notification.Failure;
-
-/**
- * A stacktrace writer that requires at least junit 4.6 to run. Note that we only use this for 4.8 and higher
- * <br>
- * Writes out a specific {@link org.junit.runner.notification.Failure} for
- * surefire as a stacktrace.
- *
- * @author Karl M. Davis
- * @author Kristian Rosenvold
- */
-public class JUnit46StackTraceWriter
-    extends JUnit4StackTraceWriter
-{
-
-    /**
-     * Constructor.
-     *
-     * @param junitFailure the {@link org.junit.runner.notification.Failure} that this will be operating on
-     */
-    public JUnit46StackTraceWriter( Failure junitFailure )
-    {
-        super( junitFailure );
-    }
-
-
-    @Override
-    protected final String getTestClassName()
-    {
-        return junitFailure.getDescription().getClassName();
-    }
-
-    @Override
-    protected String getTestMethodName()
-    {
-        return junitFailure.getDescription().getMethodName();
-    }
-}
diff --git a/surefire-providers/surefire-junit-platform/pom.xml b/surefire-providers/surefire-junit-platform/pom.xml
index 76bc92c..e551fef 100644
--- a/surefire-providers/surefire-junit-platform/pom.xml
+++ b/surefire-providers/surefire-junit-platform/pom.xml
@@ -139,6 +139,10 @@
                 <version>3.0.0-M3</version> <!-- ${shadedVersion}, but resolved due to https://issues.apache.org/jira/browse/MRELEASE-799 -->
                 <configuration>
                     <jvm>${java.home}/bin/java</jvm>
+                    <redirectTestOutputToFile>true</redirectTestOutputToFile>
+                    <includes>
+                        <include>**/JUnit47SuiteTest.java</include>
+                    </includes>
                 </configuration>
             </plugin>
         </plugins>
diff --git a/surefire-providers/surefire-junit-platform/src/main/java/org/apache/maven/surefire/junitplatform/RunListenerAdapter.java b/surefire-providers/surefire-junit-platform/src/main/java/org/apache/maven/surefire/junitplatform/RunListenerAdapter.java
index 71c8bc0..943f12a 100644
--- a/surefire-providers/surefire-junit-platform/src/main/java/org/apache/maven/surefire/junitplatform/RunListenerAdapter.java
+++ b/surefire-providers/surefire-junit-platform/src/main/java/org/apache/maven/surefire/junitplatform/RunListenerAdapter.java
@@ -20,15 +20,12 @@ package org.apache.maven.surefire.junitplatform;
  */
 
 import static java.util.Collections.emptyMap;
-import static org.apache.maven.surefire.report.SimpleReportEntry.ignored;
 import static org.apache.maven.surefire.util.internal.ObjectUtils.systemProps;
-import static org.junit.platform.engine.TestExecutionResult.Status.ABORTED;
-import static org.junit.platform.engine.TestExecutionResult.Status.FAILED;
 
 import java.util.Map;
 import java.util.Optional;
-import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
 
 import org.apache.maven.surefire.report.PojoStackTraceWriter;
 import org.apache.maven.surefire.report.RunListener;
@@ -41,7 +38,6 @@ import org.junit.platform.engine.support.descriptor.MethodSource;
 import org.junit.platform.launcher.TestExecutionListener;
 import org.junit.platform.launcher.TestIdentifier;
 import org.junit.platform.launcher.TestPlan;
-import org.junit.platform.launcher.listeners.LegacyReportingUtils;
 
 /**
  * @since 2.22.0
@@ -49,12 +45,9 @@ import org.junit.platform.launcher.listeners.LegacyReportingUtils;
 final class RunListenerAdapter
     implements TestExecutionListener
 {
-
+    private final ConcurrentMap<TestIdentifier, Long> testStartTime = new ConcurrentHashMap<>();
     private final RunListener runListener;
-
-    private TestPlan testPlan;
-
-    private Set<TestIdentifier> testSetNodes = ConcurrentHashMap.newKeySet();
+    private volatile TestPlan testPlan;
 
     RunListenerAdapter( RunListener runListener )
     {
@@ -64,13 +57,14 @@ final class RunListenerAdapter
     @Override
     public void testPlanExecutionStarted( TestPlan testPlan )
     {
-        updateTestPlan( testPlan );
+        this.testPlan = testPlan;
     }
 
     @Override
     public void testPlanExecutionFinished( TestPlan testPlan )
     {
-        updateTestPlan( null );
+        this.testPlan = null;
+        testStartTime.clear();
     }
 
     @Override
@@ -79,111 +73,99 @@ final class RunListenerAdapter
         if ( testIdentifier.isContainer()
                         && testIdentifier.getSource().filter( ClassSource.class::isInstance ).isPresent() )
         {
-            startTestSetIfPossible( testIdentifier );
-        }
-        if ( testIdentifier.isTest() )
-        {
-            ensureTestSetStarted( testIdentifier );
-            runListener.testStarting( createReportEntry( testIdentifier ) );
-        }
-    }
-
-    @Override
-    public void executionSkipped( TestIdentifier testIdentifier, String reason )
-    {
-        ensureTestSetStarted( testIdentifier );
-        String source = getLegacyReportingClassName( testIdentifier );
-        runListener.testSkipped( ignored( source, getLegacyReportingName( testIdentifier ), reason ) );
-        completeTestSetIfNecessary( testIdentifier );
-    }
-
-    @Override
-    public void executionFinished(
-                    TestIdentifier testIdentifier, TestExecutionResult testExecutionResult )
-    {
-        if ( testExecutionResult.getStatus() == ABORTED )
-        {
-            runListener.testAssumptionFailure( createReportEntry( testIdentifier, testExecutionResult ) );
-        }
-        else if ( testExecutionResult.getStatus() == FAILED )
-        {
-            reportFailedTest( testIdentifier, testExecutionResult );
+            testStartTime.put( testIdentifier, System.currentTimeMillis() );
+            runListener.testSetStarting( createTestSetReportEntry( testIdentifier, systemProps() ) );
         }
         else if ( testIdentifier.isTest() )
         {
-            runListener.testSucceeded( createReportEntry( testIdentifier ) );
+            testStartTime.put( testIdentifier, System.currentTimeMillis() );
+            runListener.testStarting( createTestSetReportEntry( testIdentifier ) );
         }
-        completeTestSetIfNecessary( testIdentifier );
-    }
-
-    private void updateTestPlan( TestPlan testPlan )
-    {
-        this.testPlan = testPlan;
-        testSetNodes.clear();
     }
 
-    private void ensureTestSetStarted( TestIdentifier testIdentifier )
-    {
-        if ( isTestSetStarted( testIdentifier ) )
-        {
-            return;
-        }
-        if ( testIdentifier.isTest() )
-        {
-            startTestSet( testPlan.getParent( testIdentifier ).orElse( testIdentifier ) );
-        }
-        else
-        {
-            startTestSet( testIdentifier );
-        }
-    }
-
-    private boolean isTestSetStarted( TestIdentifier testIdentifier )
+    @Override
+    public void executionFinished( TestIdentifier testIdentifier, TestExecutionResult testExecutionResult )
     {
-        return testSetNodes.contains( testIdentifier )
-                        || testPlan.getParent( testIdentifier ).map( this::isTestSetStarted ).orElse( false );
-    }
+        boolean isClass = testIdentifier.isContainer()
+                && testIdentifier.getSource().filter( ClassSource.class::isInstance ).isPresent();
 
-    private void startTestSetIfPossible( TestIdentifier testIdentifier )
-    {
-        if ( !isTestSetStarted( testIdentifier ) )
-        {
-            startTestSet( testIdentifier );
-        }
-    }
+        boolean isTest = testIdentifier.isTest();
 
-    private void completeTestSetIfNecessary( TestIdentifier testIdentifier )
-    {
-        if ( testSetNodes.contains( testIdentifier ) )
+        if ( isClass || isTest )
         {
-            completeTestSet( testIdentifier );
+            Integer elapsed = computeElapsedTime( testIdentifier );
+            switch ( testExecutionResult.getStatus() )
+            {
+                case ABORTED:
+                    if ( isTest )
+                    {
+                        runListener.testAssumptionFailure(
+                                createReportEntry( testIdentifier, testExecutionResult, elapsed ) );
+                    }
+                    else
+                    {
+                        runListener.testSetCompleted(
+                                createTestSetReportEntry( testIdentifier, testExecutionResult, emptyMap(), elapsed ) );
+                    }
+                    break;
+                case FAILED:
+                    if ( !isTest )
+                    {
+                        runListener.testSetCompleted(
+                                createTestSetReportEntry( testIdentifier, testExecutionResult, emptyMap(), elapsed ) );
+                    }
+                    else if ( testExecutionResult.getThrowable()
+                            .filter( AssertionError.class::isInstance ).isPresent() )
+                    {
+                        runListener.testFailed( createReportEntry( testIdentifier, testExecutionResult, elapsed ) );
+                    }
+                    else
+                    {
+                        runListener.testError( createReportEntry( testIdentifier, testExecutionResult, elapsed ) );
+                    }
+                    break;
+                default:
+                    if ( isTest )
+                    {
+                        runListener.testSucceeded( createReportEntry( testIdentifier, elapsed ) );
+                    }
+                    else
+                    {
+                        runListener.testSetCompleted(
+                                createTestSetReportEntry( testIdentifier, null, emptyMap(), elapsed ) );
+                    }
+            }
         }
     }
 
-    private void startTestSet( TestIdentifier testIdentifier )
+    private Integer computeElapsedTime( TestIdentifier testIdentifier )
     {
-        runListener.testSetStarting( createTestSetReportEntry( testIdentifier ) );
-        testSetNodes.add( testIdentifier );
+        Long startTime = testStartTime.remove( testIdentifier );
+        long endTime = System.currentTimeMillis();
+        return startTime == null ? null : (int) ( endTime - startTime );
     }
 
-    private void completeTestSet( TestIdentifier testIdentifier )
+    @Override
+    public void executionSkipped( TestIdentifier testIdentifier, String reason )
     {
-        runListener.testSetCompleted( createTestSetReportEntry( testIdentifier, systemProps() ) );
-        testSetNodes.remove( testIdentifier );
+        testStartTime.remove( testIdentifier );
+        String[] classMethodName = toClassMethodName( testIdentifier );
+        String className = classMethodName[1];
+        String methodName = classMethodName[3];
+        runListener.testSkipped( new SimpleReportEntry( className, methodName, reason ) );
     }
 
-    private void reportFailedTest(
-                    TestIdentifier testIdentifier, TestExecutionResult testExecutionResult )
+    private SimpleReportEntry createTestSetReportEntry( TestIdentifier testIdentifier,
+                                                        TestExecutionResult testExecutionResult,
+                                                        Map<String, String> systemProperties,
+                                                        Integer elapsedTime )
     {
-        SimpleReportEntry reportEntry = createReportEntry( testIdentifier, testExecutionResult );
-        if ( testExecutionResult.getThrowable().filter( AssertionError.class::isInstance ).isPresent() )
-        {
-            runListener.testFailed( reportEntry );
-        }
-        else
-        {
-            runListener.testError( reportEntry );
-        }
+        String[] classMethodName = toClassMethodName( testIdentifier );
+        String className = classMethodName[1];
+        String methodName = classMethodName[3];
+        StackTraceWriter stw =
+                testExecutionResult == null ? null : toStackTraceWriter( className, methodName, testExecutionResult );
+        return new SimpleReportEntry( className, methodName, stw, elapsedTime, systemProperties );
     }
 
     private SimpleReportEntry createTestSetReportEntry( TestIdentifier testIdentifier )
@@ -194,88 +176,101 @@ final class RunListenerAdapter
     private SimpleReportEntry createTestSetReportEntry( TestIdentifier testIdentifier,
                                                         Map<String, String> systemProperties )
     {
-        return new SimpleReportEntry( JUnitPlatformProvider.class.getName(),
-                testIdentifier.getLegacyReportingName(), systemProperties );
+        return createTestSetReportEntry( testIdentifier, null, systemProperties, null );
     }
 
-    private SimpleReportEntry createReportEntry( TestIdentifier testIdentifier )
+    private SimpleReportEntry createReportEntry( TestIdentifier testIdentifier, Integer elapsedTime )
     {
-        return createReportEntry( testIdentifier, (StackTraceWriter) null );
+        return createReportEntry( testIdentifier, (StackTraceWriter) null, elapsedTime );
     }
 
-    private SimpleReportEntry createReportEntry(
-                    TestIdentifier testIdentifier, TestExecutionResult testExecutionResult )
+    private SimpleReportEntry createReportEntry( TestIdentifier testIdentifier,
+                                                 TestExecutionResult testExecutionResult, Integer elapsedTime )
     {
-        return createReportEntry(
-                        testIdentifier, getStackTraceWriter( testIdentifier, testExecutionResult ) );
+        String[] classMethodNames = toClassMethodName( testIdentifier );
+        String realClassName = classMethodNames[0];
+        String realMethodName = classMethodNames[2];
+        return createReportEntry( testIdentifier,
+                toStackTraceWriter( realClassName, realMethodName, testExecutionResult ), elapsedTime );
     }
 
-    private SimpleReportEntry createReportEntry(
-                    TestIdentifier testIdentifier, StackTraceWriter stackTraceWriter )
+    private SimpleReportEntry createReportEntry( TestIdentifier testIdentifier, StackTraceWriter stackTraceWriter,
+                                                 Integer elapsedTime )
     {
-        String source = getLegacyReportingClassName( testIdentifier );
-        String name = getLegacyReportingName( testIdentifier );
-
-        return SimpleReportEntry.withException( source, name, stackTraceWriter );
-    }
-
-    private String getLegacyReportingName( TestIdentifier testIdentifier )
-    {
-        // Surefire cuts off the name at the first '(' character. Thus, we have to pick a different
-        // character to represent parentheses. "()" are removed entirely to maximize compatibility with
-        // existing reporting tools because in the old days test methods used to not have parameters.
-        return testIdentifier
-                        .getLegacyReportingName()
-                        .replace( "()", "" )
-                        .replace( '(', '{' )
-                        .replace( ')', '}' );
+        String[] classMethodNames = toClassMethodName( testIdentifier );
+        String className = classMethodNames[1];
+        String methodName = classMethodNames[3];
+        return new SimpleReportEntry( className, methodName, stackTraceWriter, elapsedTime );
     }
 
-    private String getLegacyReportingClassName( TestIdentifier testIdentifier )
+    private StackTraceWriter toStackTraceWriter( String realClassName, String realMethodName,
+                                                 TestExecutionResult testExecutionResult )
     {
-        return LegacyReportingUtils.getClassName( testPlan, testIdentifier );
-    }
-
-    private StackTraceWriter getStackTraceWriter(
-                    TestIdentifier testIdentifier, TestExecutionResult testExecutionResult )
-    {
-        Optional<Throwable> throwable = testExecutionResult.getThrowable();
-        if ( testExecutionResult.getStatus() == FAILED )
+        switch ( testExecutionResult.getStatus() )
         {
-            // Failed tests must have a StackTraceWriter, otherwise Surefire will fail
-            return getStackTraceWriter( testIdentifier, throwable.orElse( null ) );
+            case ABORTED:
+            case FAILED:
+                // Failed tests must have a StackTraceWriter, otherwise Surefire will fail
+                Throwable exception = testExecutionResult.getThrowable().orElse( null );
+                return toStackTraceWriter( realClassName, realMethodName, exception );
+            default:
+                return testExecutionResult.getThrowable()
+                        .map( t -> toStackTraceWriter( realClassName, realMethodName, t ) )
+                        .orElse( null );
         }
-        return throwable.map( t -> getStackTraceWriter( testIdentifier, t ) ).orElse( null );
     }
 
-    private StackTraceWriter getStackTraceWriter( TestIdentifier testIdentifier, Throwable throwable )
+    private StackTraceWriter toStackTraceWriter( String realClassName, String realMethodName, Throwable throwable )
     {
-        String className = getClassName( testIdentifier );
-        String methodName = getMethodName( testIdentifier ).orElse( "" );
-        return new PojoStackTraceWriter( className, methodName, throwable );
+        return new PojoStackTraceWriter( realClassName, realMethodName, throwable );
     }
 
-    private String getClassName( TestIdentifier testIdentifier )
+    /**
+     * <ul>
+     *     <li>[0] class name - used in stacktrace parser</li>
+     *     <li>[1] class display name</li>
+     *     <li>[2] method signature - used in stacktrace parser</li>
+     *     <li>[3] method display name</li>
+     * </ul>
+     *
+     * @param testIdentifier a class or method
+     * @return 4 elements string array
+     */
+    private String[] toClassMethodName( TestIdentifier testIdentifier )
     {
-        TestSource testSource = testIdentifier.getSource().orElse( null );
-        if ( testSource instanceof ClassSource )
+        Optional<TestSource> testSource = testIdentifier.getSource();
+        String display = testIdentifier.getDisplayName();
+
+        if ( testSource.filter( MethodSource.class::isInstance ).isPresent() )
         {
-            return ( (ClassSource) testSource ).getJavaClass().getName();
+            MethodSource methodSource = testSource.map( MethodSource.class::cast ).get();
+            String realClassName = methodSource.getClassName();
+
+            String[] source = testPlan.getParent( testIdentifier )
+                    .map( this::toClassMethodName )
+                    .map( s -> new String[] { s[0], s[1] } )
+                    .orElse( new String[] { realClassName, realClassName } );
+
+            String methodName = methodSource.getMethodName();
+            boolean useMethod = display.equals( methodName ) || display.equals( methodName + "()" );
+            String resolvedMethodName = useMethod ? methodName : display;
+
+            return new String[] { source[0], source[1], methodName, resolvedMethodName };
         }
-        if ( testSource instanceof MethodSource )
+        else if ( testSource.filter( ClassSource.class::isInstance ).isPresent() )
         {
-            return ( (MethodSource) testSource ).getClassName();
+            ClassSource classSource = testSource.map( ClassSource.class::cast ).get();
+            String className = classSource.getClassName();
+            String simpleClassName = className.substring( 1 + className.lastIndexOf( '.' ) );
+            String source = display.equals( simpleClassName ) ? className : display;
+            return new String[] { source, source, null, null };
         }
-        return testPlan.getParent( testIdentifier ).map( this::getClassName ).orElse( "" );
-    }
-
-    private Optional<String> getMethodName( TestIdentifier testIdentifier )
-    {
-        TestSource testSource = testIdentifier.getSource().orElse( null );
-        if ( testSource instanceof MethodSource )
+        else
         {
-            return Optional.of( ( (MethodSource) testSource ).getMethodName() );
+            String source = testPlan.getParent( testIdentifier )
+                    .map( TestIdentifier::getDisplayName )
+                    .orElse( display );
+            return new String[] { source, source, display, display };
         }
-        return Optional.empty();
     }
 }
diff --git a/surefire-providers/common-junit4/src/main/java/org/apache/maven/surefire/common/junit4/ClassMethod.java b/surefire-providers/surefire-junit-platform/src/test/java/org/apache/maven/surefire/junitplatform/JUnit47SuiteTest.java
similarity index 56%
rename from surefire-providers/common-junit4/src/main/java/org/apache/maven/surefire/common/junit4/ClassMethod.java
rename to surefire-providers/surefire-junit-platform/src/test/java/org/apache/maven/surefire/junitplatform/JUnit47SuiteTest.java
index a3cccca..d0d4af9 100644
--- a/surefire-providers/common-junit4/src/main/java/org/apache/maven/surefire/common/junit4/ClassMethod.java
+++ b/surefire-providers/surefire-junit-platform/src/test/java/org/apache/maven/surefire/junitplatform/JUnit47SuiteTest.java
@@ -1,4 +1,4 @@
-package org.apache.maven.surefire.common.junit4;
+package org.apache.maven.surefire.junitplatform;
 
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
@@ -19,35 +19,28 @@ package org.apache.maven.surefire.common.junit4;
  * under the License.
  */
 
-import org.apache.maven.surefire.util.internal.StringUtils;
+import junit.framework.JUnit4TestAdapter;
+import junit.framework.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Suite;
+import org.junit.runners.Suite.SuiteClasses;
 
 /**
- * Data transfer object of class and method literals.
+ * Adapt the JUnit4 tests which use only annotations to the JUnit3 test suite.
+ *
+ * @since 3.0.0-M4
  */
-public final class ClassMethod
+@SuiteClasses( {
+        JUnitPlatformProviderTest.class,
+        RunListenerAdapterTest.class,
+        TestMethodFilterTest.class,
+        TestPlanScannerFilterTest.class
+} )
+@RunWith( Suite.class )
+public class JUnit47SuiteTest
 {
-    private final String clazz;
-
-    private final String method;
-
-    public ClassMethod( String clazz, String method )
-    {
-        this.clazz = clazz;
-        this.method = method;
-    }
-
-    public boolean isValid()
-    {
-        return !StringUtils.isBlank( clazz ) && !StringUtils.isBlank( method );
-    }
-
-    public String getClazz()
-    {
-        return clazz;
-    }
-
-    public String getMethod()
+    public static Test suite()
     {
-        return method;
+        return new JUnit4TestAdapter( JUnit47SuiteTest.class );
     }
 }
diff --git a/surefire-providers/surefire-junit-platform/src/test/java/org/apache/maven/surefire/junitplatform/JUnitPlatformProviderTest.java b/surefire-providers/surefire-junit-platform/src/test/java/org/apache/maven/surefire/junitplatform/JUnitPlatformProviderTest.java
index c162905..f6b48e9 100644
--- a/surefire-providers/surefire-junit-platform/src/test/java/org/apache/maven/surefire/junitplatform/JUnitPlatformProviderTest.java
+++ b/surefire-providers/surefire-junit-platform/src/test/java/org/apache/maven/surefire/junitplatform/JUnitPlatformProviderTest.java
@@ -60,6 +60,7 @@ import org.apache.maven.surefire.testset.TestSetFailedException;
 import org.apache.maven.surefire.util.RunOrderCalculator;
 import org.apache.maven.surefire.util.ScanResult;
 import org.apache.maven.surefire.util.TestsToRun;
+import org.fest.assertions.Assertions;
 import org.junit.Test;
 import org.junit.jupiter.api.Disabled;
 import org.junit.platform.launcher.Launcher;
@@ -163,30 +164,38 @@ public class JUnitPlatformProviderTest
         invokeProvider( provider, null );
 
         InOrder inOrder = inOrder( runListener );
-        inOrder
-                        .verify( runListener )
-                        .testSetStarting(
-                                        new SimpleReportEntry(
-                                                        JUnitPlatformProvider.class.getName(),
-                                                        TestClass1.class.getName() ) );
-        inOrder
-                        .verify( runListener )
-                        .testSetCompleted(
-                                        new SimpleReportEntry(
-                                                        JUnitPlatformProvider.class.getName(),
-                                                        TestClass1.class.getName() ) );
-        inOrder
-                        .verify( runListener )
-                        .testSetStarting(
-                                        new SimpleReportEntry(
-                                                        JUnitPlatformProvider.class.getName(),
-                                                        TestClass2.class.getName() ) );
-        inOrder
-                        .verify( runListener )
-                        .testSetCompleted(
-                                        new SimpleReportEntry(
-                                                        JUnitPlatformProvider.class.getName(),
-                                                        TestClass2.class.getName() ) );
+
+        ArgumentCaptor<SimpleReportEntry> report = ArgumentCaptor.forClass( SimpleReportEntry.class );
+        inOrder.verify( runListener )
+                .testSetStarting( report.capture() );
+        Assertions.assertThat( report.getValue().getSourceName() )
+                .isEqualTo( TestClass1.class.getName() );
+        Assertions.assertThat( report.getValue().getName() )
+                .isNull();
+
+        report = ArgumentCaptor.forClass( SimpleReportEntry.class );
+        inOrder.verify( runListener )
+                .testSetCompleted( report.capture() );
+        Assertions.assertThat( report.getValue().getSourceName() )
+                .isEqualTo( TestClass1.class.getName() );
+        Assertions.assertThat( report.getValue().getName() )
+                .isNull();
+
+        report = ArgumentCaptor.forClass( SimpleReportEntry.class );
+        inOrder.verify( runListener )
+                .testSetStarting( report.capture() );
+        Assertions.assertThat( report.getValue().getSourceName() )
+                .isEqualTo( TestClass2.class.getName() );
+        Assertions.assertThat( report.getValue().getName() )
+                .isNull();
+
+        report = ArgumentCaptor.forClass( SimpleReportEntry.class );
+        inOrder.verify( runListener )
+                .testSetCompleted( report.capture() );
+        Assertions.assertThat( report.getValue().getSourceName() )
+                .isEqualTo( TestClass2.class.getName() );
+        Assertions.assertThat( report.getValue().getName() )
+                .isNull();
 
         assertThat( executionListener.summaries ).hasSize( 1 );
         TestExecutionSummary summary = executionListener.summaries.get( 0 );
diff --git a/surefire-providers/surefire-junit-platform/src/test/java/org/apache/maven/surefire/junitplatform/RunListenerAdapterTest.java b/surefire-providers/surefire-junit-platform/src/test/java/org/apache/maven/surefire/junitplatform/RunListenerAdapterTest.java
index 0ccb4fe..2f5c8ac 100644
--- a/surefire-providers/surefire-junit-platform/src/test/java/org/apache/maven/surefire/junitplatform/RunListenerAdapterTest.java
+++ b/surefire-providers/surefire-junit-platform/src/test/java/org/apache/maven/surefire/junitplatform/RunListenerAdapterTest.java
@@ -22,27 +22,27 @@ package org.apache.maven.surefire.junitplatform;
 import static java.util.Collections.emptyList;
 import static java.util.Collections.singleton;
 import static java.util.Collections.singletonList;
+import static org.fest.assertions.Assertions.assertThat;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertNull;
-import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.junit.platform.engine.TestDescriptor.Type.CONTAINER;
 import static org.junit.platform.engine.TestDescriptor.Type.TEST;
+import static org.junit.platform.engine.TestExecutionResult.aborted;
+import static org.junit.platform.engine.TestExecutionResult.failed;
 import static org.junit.platform.engine.TestExecutionResult.successful;
 import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.inOrder;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.verifyZeroInteractions;
-import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.*;
 
+import java.lang.reflect.Method;
 import java.util.Optional;
 
+import org.apache.maven.surefire.report.PojoStackTraceWriter;
 import org.apache.maven.surefire.report.ReportEntry;
 import org.apache.maven.surefire.report.RunListener;
 import org.apache.maven.surefire.report.SimpleReportEntry;
+import org.apache.maven.surefire.report.StackTraceWriter;
+import org.apache.maven.surefire.report.TestSetReportEntry;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.jupiter.api.DisplayName;
@@ -51,16 +51,17 @@ import org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor;
 import org.junit.platform.engine.ConfigurationParameters;
 import org.junit.platform.engine.TestDescriptor;
 import org.junit.platform.engine.TestDescriptor.Type;
-import org.junit.platform.engine.TestExecutionResult;
 import org.junit.platform.engine.TestSource;
 import org.junit.platform.engine.UniqueId;
 import org.junit.platform.engine.support.descriptor.AbstractTestDescriptor;
 import org.junit.platform.engine.support.descriptor.ClassSource;
 import org.junit.platform.engine.support.descriptor.EngineDescriptor;
+import org.junit.platform.engine.support.descriptor.MethodSource;
 import org.junit.platform.launcher.TestIdentifier;
 import org.junit.platform.launcher.TestPlan;
 import org.mockito.ArgumentCaptor;
 import org.mockito.InOrder;
+import org.opentest4j.TestSkippedException;
 
 /**
  * Unit tests for {@link RunListenerAdapter}.
@@ -69,7 +70,7 @@ import org.mockito.InOrder;
  */
 public class RunListenerAdapterTest
 {
-    private static final ConfigurationParameters CONFIG_PARAMS = mock(ConfigurationParameters.class);
+    private static final ConfigurationParameters CONFIG_PARAMS = mock( ConfigurationParameters.class );
 
     private RunListener listener;
 
@@ -120,7 +121,7 @@ public class RunListenerAdapterTest
         verify( listener ).testStarting( entryCaptor.capture() );
 
         ReportEntry entry = entryCaptor.getValue();
-        assertEquals( MY_TEST_METHOD_NAME + "{String}", entry.getName() );
+        assertEquals( MY_TEST_METHOD_NAME + "(String)", entry.getName() );
         assertEquals( MyTestClass.class.getName(), entry.getSourceName() );
         assertNull( entry.getStackTraceWriter() );
     }
@@ -139,8 +140,7 @@ public class RunListenerAdapterTest
         adapter.testPlanExecutionStarted( plan );
         adapter.executionStarted( TestIdentifier.from( engine ) );
         adapter.executionStarted( TestIdentifier.from( parent ) );
-        verify( listener ).testSetStarting( new SimpleReportEntry( JUnitPlatformProvider.class.getName(),
-                                                        MyTestClass.class.getName() ) );
+        verify( listener ).testSetStarting( new SimpleReportEntry( MyTestClass.class.getName(), null ) );
         verifyNoMoreInteractions( listener );
 
         adapter.executionStarted( TestIdentifier.from( child ) );
@@ -148,12 +148,29 @@ public class RunListenerAdapterTest
         verifyNoMoreInteractions( listener );
 
         adapter.executionFinished( TestIdentifier.from( child ), successful() );
-        verify( listener ).testSucceeded( new SimpleReportEntry( MyTestClass.class.getName(), MY_TEST_METHOD_NAME ) );
+        ArgumentCaptor<SimpleReportEntry> report = ArgumentCaptor.forClass( SimpleReportEntry.class );
+        verify( listener ).testSucceeded( report.capture() );
+        assertThat( report.getValue().getSourceName() )
+                .isEqualTo( MyTestClass.class.getName() );
+        assertThat( report.getValue().getName() )
+                .isEqualTo( MY_TEST_METHOD_NAME );
+        assertThat( report.getValue().getElapsed() )
+                .isNotNull();
+        assertThat( report.getValue().getSystemProperties() )
+                .isEmpty();
         verifyNoMoreInteractions( listener );
 
         adapter.executionFinished( TestIdentifier.from( parent ), successful() );
-        verify( listener ).testSetCompleted( new SimpleReportEntry( JUnitPlatformProvider.class.getName(),
-                                                        MyTestClass.class.getName() ) );
+        report = ArgumentCaptor.forClass( SimpleReportEntry.class );
+        verify( listener ).testSetCompleted( report.capture() );
+        assertThat( report.getValue().getSourceName() )
+                .isEqualTo( MyTestClass.class.getName() );
+        assertThat( report.getValue().getName() )
+                .isNull();
+        assertThat( report.getValue().getElapsed() )
+                .isNotNull();
+        assertThat( report.getValue().getSystemProperties() )
+                .isEmpty();
         verifyNoMoreInteractions( listener );
 
         adapter.executionFinished( TestIdentifier.from( engine ), successful() );
@@ -161,11 +178,10 @@ public class RunListenerAdapterTest
     }
 
     @Test
-    public void notifiedLazilyForTestSetWhenFirstTestWithoutClassDescriptorParentStarted()
+    public void displayNamesInClassAndMethods()
     {
         EngineDescriptor engine = newEngineDescriptor();
-        TestDescriptor parent = newTestDescriptor( engine.getUniqueId().append( "container", "noClass" ), "parent",
-                                        CONTAINER );
+        TestDescriptor parent = newClassDescriptor( "parent" );
         engine.addChild( parent );
         TestDescriptor child1 = newTestDescriptor( parent.getUniqueId().append( "test", "child1" ), "child1", TEST );
         parent.addChild( child1 );
@@ -173,33 +189,66 @@ public class RunListenerAdapterTest
         parent.addChild( child2 );
         TestPlan plan = TestPlan.from( singletonList( engine ) );
 
+        InOrder inOrder = inOrder( listener );
+
         adapter.testPlanExecutionStarted( plan );
+
         adapter.executionStarted( TestIdentifier.from( engine ) );
         adapter.executionStarted( TestIdentifier.from( parent ) );
+        ArgumentCaptor<SimpleReportEntry> report = ArgumentCaptor.forClass( SimpleReportEntry.class );
+        inOrder.verify( listener ).testSetStarting( report.capture() );
+        assertThat( report.getValue().getSourceName() )
+                .isEqualTo( "parent" );
+        assertThat( report.getValue().getName() )
+                .isNull();
+        assertThat( report.getValue().getSystemProperties() )
+                .isNotEmpty();
         verifyZeroInteractions( listener );
 
         adapter.executionStarted( TestIdentifier.from( child1 ) );
-        InOrder inOrder = inOrder( listener );
-        inOrder.verify( listener )
-                .testSetStarting( new SimpleReportEntry( JUnitPlatformProvider.class.getName(), "parent" ) );
         inOrder.verify( listener ).testStarting( new SimpleReportEntry( "parent", "child1" ) );
-        inOrder.verifyNoMoreInteractions();
+        verifyNoMoreInteractions( listener );
 
         adapter.executionFinished( TestIdentifier.from( child1 ), successful() );
-        verify( listener ).testSucceeded( new SimpleReportEntry( "parent", "child1" ) );
+        report = ArgumentCaptor.forClass( SimpleReportEntry.class );
+        inOrder.verify( listener ).testSucceeded( report.capture() );
+        assertThat( report.getValue().getSourceName() )
+                .isEqualTo( "parent" );
+        assertThat( report.getValue().getName() )
+                .isEqualTo( "child1" );
+        assertThat( report.getValue().getElapsed() )
+                .isNotNull();
+        assertThat( report.getValue().getSystemProperties() )
+                .isEmpty();
         verifyNoMoreInteractions( listener );
 
         adapter.executionStarted( TestIdentifier.from( child2 ) );
-        verify( listener ).testStarting( new SimpleReportEntry( "parent", "child2" ) );
+        inOrder.verify( listener ).testStarting( new SimpleReportEntry( "parent", "child2" ) );
         verifyNoMoreInteractions( listener );
 
         adapter.executionFinished( TestIdentifier.from( child2 ), successful() );
-        verify( listener ).testSucceeded( new SimpleReportEntry( "parent", "child2" ) );
+        report = ArgumentCaptor.forClass( SimpleReportEntry.class );
+        inOrder.verify( listener ).testSucceeded( report.capture() );
+        assertThat( report.getValue().getSourceName() )
+                .isEqualTo( "parent" );
+        assertThat( report.getValue().getName() )
+                .isEqualTo( "child2" );
+        assertThat( report.getValue().getElapsed() )
+                .isNotNull();
+        assertThat( report.getValue().getSystemProperties() )
+                .isEmpty();
         verifyNoMoreInteractions( listener );
 
         adapter.executionFinished( TestIdentifier.from( parent ), successful() );
-        verify( listener )
-                        .testSetCompleted( new SimpleReportEntry( JUnitPlatformProvider.class.getName(), "parent" ) );
+        inOrder.verify( listener ).testSetCompleted( report.capture() );
+        assertThat( report.getValue().getSourceName() )
+                .isEqualTo( "parent" );
+        assertThat( report.getValue().getName() )
+                .isNull();
+        assertThat( report.getValue().getElapsed() )
+                .isNotNull();
+        assertThat( report.getValue().getSystemProperties() )
+                .isEmpty();
         verifyNoMoreInteractions( listener );
 
         adapter.executionFinished( TestIdentifier.from( engine ), successful() );
@@ -207,7 +256,7 @@ public class RunListenerAdapterTest
     }
 
     @Test
-    public void notifiedForTestSetForSingleNodeEngine()
+    public void notifiedForUnclassifiedTestIdentifier()
     {
         EngineDescriptor engine = new EngineDescriptor( UniqueId.forEngine( "engine" ), "engine" )
         {
@@ -221,18 +270,21 @@ public class RunListenerAdapterTest
 
         adapter.testPlanExecutionStarted( plan );
         adapter.executionStarted( TestIdentifier.from( engine ) );
-        InOrder inOrder = inOrder( listener );
-        inOrder.verify( listener )
-                .testSetStarting( new SimpleReportEntry( JUnitPlatformProvider.class.getName(), "engine" ) );
-        inOrder.verify( listener ).testStarting( new SimpleReportEntry( "<unrooted>", "engine" ) );
-        inOrder.verifyNoMoreInteractions();
+        verify( listener ).testStarting( new SimpleReportEntry( "engine", "engine" ) );
+        verifyNoMoreInteractions( listener );
 
         adapter.executionFinished( TestIdentifier.from( engine ), successful() );
-        inOrder = inOrder( listener );
-        inOrder.verify( listener ).testSucceeded( new SimpleReportEntry( "<unrooted>", "engine" ) );
-        inOrder.verify( listener )
-                .testSetCompleted( new SimpleReportEntry( JUnitPlatformProvider.class.getName(), "engine" ) );
-        inOrder.verifyNoMoreInteractions();
+        ArgumentCaptor<SimpleReportEntry> report = ArgumentCaptor.forClass( SimpleReportEntry.class );
+        verify( listener ).testSucceeded( report.capture() );
+        assertThat( report.getValue().getSourceName() )
+                .isEqualTo( "engine" );
+        assertThat( report.getValue().getName() )
+                .isEqualTo( "engine" );
+        assertThat( report.getValue().getElapsed() )
+                .isNotNull();
+        assertThat( report.getValue().getSystemProperties() )
+                .isEmpty();
+        verifyNoMoreInteractions( listener );
     }
 
     @Test
@@ -264,7 +316,7 @@ public class RunListenerAdapterTest
         verify( listener ).testSkipped( entryCaptor.capture() );
 
         ReportEntry entry = entryCaptor.getValue();
-        assertTrue( MyTestClass.class.getTypeName().contains( entry.getName() ) );
+        assertNull( entry.getName() );
         assertEquals( MyTestClass.class.getTypeName(), entry.getSourceName() );
     }
 
@@ -279,48 +331,59 @@ public class RunListenerAdapterTest
     public void notifiedWhenMethodExecutionAborted()
                     throws Exception
     {
-        adapter.executionFinished( newMethodIdentifier(), TestExecutionResult.aborted( null ) );
+        adapter.executionFinished( newMethodIdentifier(), aborted( null ) );
         verify( listener ).testAssumptionFailure( any() );
     }
 
     @Test
     public void notifiedWhenClassExecutionAborted()
     {
-        adapter.executionFinished( newClassIdentifier(), TestExecutionResult.aborted( null ) );
-        verify( listener ).testAssumptionFailure( any() );
+        TestSkippedException t = new TestSkippedException( "skipped" );
+        adapter.executionFinished( newClassIdentifier(), aborted( t ) );
+        String source = MyTestClass.class.getName();
+        StackTraceWriter stw = new PojoStackTraceWriter( source, null, t );
+        ArgumentCaptor<SimpleReportEntry> report = ArgumentCaptor.forClass( SimpleReportEntry.class );
+        verify( listener ).testSetCompleted( report.capture() );
+        assertThat( report.getValue().getSourceName() )
+                .isEqualTo( source );
+        assertThat( report.getValue().getStackTraceWriter() )
+                .isEqualTo( stw );
     }
 
     @Test
-    public void notifiedWhenMethodExecutionFailedWithAnAssertionError()
+    public void notifiedWhenMethodExecutionFailed()
                     throws Exception
     {
-        adapter.executionFinished( newMethodIdentifier(), TestExecutionResult.failed( new AssertionError() ) );
+        adapter.executionFinished( newMethodIdentifier(), failed( new AssertionError() ) );
         verify( listener ).testFailed( any() );
     }
 
     @Test
-    public void notifiedWhenMethodExecutionFailedWithANonAssertionError()
+    public void notifiedWhenMethodExecutionFailedWithError()
                     throws Exception
     {
-        adapter.executionFinished( newMethodIdentifier(), TestExecutionResult.failed( new RuntimeException() ) );
+        adapter.executionFinished( newMethodIdentifier(), failed( new RuntimeException() ) );
         verify( listener ).testError( any() );
     }
 
     @Test
     public void notifiedWithCorrectNamesWhenClassExecutionFailed()
     {
-        ArgumentCaptor<ReportEntry> entryCaptor = ArgumentCaptor.forClass( ReportEntry.class );
+        ArgumentCaptor<TestSetReportEntry> entryCaptor = ArgumentCaptor.forClass( TestSetReportEntry.class );
         TestPlan testPlan = TestPlan.from( singletonList( new EngineDescriptor( newId(), "Luke's Plan" ) ) );
         adapter.testPlanExecutionStarted( testPlan );
 
-        adapter.executionFinished(
-                        identifiersAsParentOnTestPlan( testPlan, newEngineDescriptor(), newClassDescriptor() ),
-                        TestExecutionResult.failed( new AssertionError() ) );
-        verify( listener ).testFailed( entryCaptor.capture() );
+        adapter.executionFinished( identifiersAsParentOnTestPlan( testPlan, newClassDescriptor() ),
+                failed( new AssertionError() ) );
+        verify( listener ).testSetCompleted( entryCaptor.capture() );
 
         ReportEntry entry = entryCaptor.getValue();
         assertEquals( MyTestClass.class.getTypeName(), entry.getSourceName() );
+        assertNull( entry.getName() );
         assertNotNull( entry.getStackTraceWriter() );
+        assertNotNull( entry.getStackTraceWriter().getThrowable() );
+        assertThat( entry.getStackTraceWriter().getThrowable().getTarget() )
+                .isInstanceOf( AssertionError.class );
     }
 
     @Test
@@ -342,8 +405,18 @@ public class RunListenerAdapterTest
 
         adapter.executionFinished( TestIdentifier.from( classDescriptor ), successful() );
 
-        verify( listener ).testSetCompleted( new SimpleReportEntry( JUnitPlatformProvider.class.getName(),
-                MyTestClass.class.getName() ) );
+        verify( listener ).testSetStarting( new SimpleReportEntry( MyTestClass.class.getName(), null ) );
+
+        ArgumentCaptor<SimpleReportEntry> report = ArgumentCaptor.forClass( SimpleReportEntry.class );
+        verify( listener ).testSetCompleted( report.capture() );
+        assertThat( report.getValue().getSourceName() )
+                .isEqualTo( MyTestClass.class.getName() );
+        assertThat( report.getValue().getName() )
+                .isNull();
+        assertThat( report.getValue().getStackTraceWriter() )
+                .isNull();
+        assertThat( report.getValue().getElapsed() )
+                .isNotNull();
 
         verify( listener, never() ).testSucceeded( any() );
     }
@@ -375,7 +448,7 @@ public class RunListenerAdapterTest
 
         TestIdentifier child =
                 newSourcelessChildIdentifierWithParent( plan, "Parent", ClassSource.from( MyTestClass.class ) );
-        adapter.executionFinished( child, TestExecutionResult.failed( new RuntimeException() ) );
+        adapter.executionFinished( child, failed( new RuntimeException() ) );
         ArgumentCaptor<ReportEntry> entryCaptor = ArgumentCaptor.forClass( ReportEntry.class );
         verify( listener ).testError( entryCaptor.capture() );
         assertNotNull( entryCaptor.getValue().getStackTraceWriter() );
@@ -388,7 +461,7 @@ public class RunListenerAdapterTest
         adapter.testPlanExecutionStarted( plan );
 
         TestIdentifier child = newSourcelessChildIdentifierWithParent( plan, "Parent", null );
-        adapter.executionFinished( child, TestExecutionResult.failed( new RuntimeException( "message" ) ) );
+        adapter.executionFinished( child, failed( new RuntimeException( "message" ) ) );
         ArgumentCaptor<ReportEntry> entryCaptor = ArgumentCaptor.forClass( ReportEntry.class );
         verify( listener ).testError( entryCaptor.capture() );
         assertNotNull( entryCaptor.getValue().getStackTraceWriter() );
@@ -401,7 +474,7 @@ public class RunListenerAdapterTest
     public void stackTraceWriterPresentEvenWithoutException()
                     throws Exception
     {
-        adapter.executionFinished( newMethodIdentifier(), TestExecutionResult.failed( null ) );
+        adapter.executionFinished( newMethodIdentifier(), failed( null ) );
         ArgumentCaptor<ReportEntry> entryCaptor = ArgumentCaptor.forClass( ReportEntry.class );
         verify( listener ).testError( entryCaptor.capture() );
         assertNotNull( entryCaptor.getValue().getStackTraceWriter() );
@@ -411,8 +484,22 @@ public class RunListenerAdapterTest
     public void displayNamesIgnoredInReport()
                     throws NoSuchMethodException
     {
-        TestMethodTestDescriptor descriptor = new TestMethodTestDescriptor( newId(), MyTestClass.class,
-                MyTestClass.class.getDeclaredMethod( "myNamedTestMethod" ) );
+        class TestMethodTestDescriptorWithDisplayName extends AbstractTestDescriptor
+        {
+            private TestMethodTestDescriptorWithDisplayName( UniqueId uniqueId, Class<?> testClass, Method testMethod )
+            {
+                super( uniqueId, "some display name", MethodSource.from( testClass, testMethod ) );
+            }
+
+            @Override
+            public Type getType()
+            {
+                return Type.TEST;
+            }
+        }
+
+        TestMethodTestDescriptorWithDisplayName descriptor = new TestMethodTestDescriptorWithDisplayName( newId(),
+                MyTestClass.class, MyTestClass.class.getDeclaredMethod( "myNamedTestMethod" ) );
 
         TestIdentifier factoryIdentifier = TestIdentifier.from( descriptor );
         ArgumentCaptor<ReportEntry> entryCaptor = ArgumentCaptor.forClass( ReportEntry.class );
@@ -422,7 +509,7 @@ public class RunListenerAdapterTest
 
         ReportEntry value = entryCaptor.getValue();
 
-        assertEquals( "myNamedTestMethod", value.getName() );
+        assertEquals( "some display name", value.getName() );
     }
 
     private static TestIdentifier newMethodIdentifier()
@@ -445,9 +532,16 @@ public class RunListenerAdapterTest
         return TestIdentifier.from( newClassDescriptor() );
     }
 
+    private static TestDescriptor newClassDescriptor( String displayName )
+    {
+        return new ClassTestDescriptor( UniqueId.root( "class", MyTestClass.class.getName() ),
+                c -> displayName, MyTestClass.class, CONFIG_PARAMS ) {};
+    }
+
     private static TestDescriptor newClassDescriptor()
     {
-        return new ClassTestDescriptor( UniqueId.root( "class", MyTestClass.class.getName() ), MyTestClass.class, CONFIG_PARAMS );
+        return new ClassTestDescriptor( UniqueId.root( "class", MyTestClass.class.getName() ),
+                MyTestClass.class, CONFIG_PARAMS );
     }
 
     private static TestIdentifier newSourcelessChildIdentifierWithParent(
@@ -516,6 +610,13 @@ public class RunListenerAdapterTest
         return childIdentifier;
     }
 
+    private static TestIdentifier identifiersAsParentOnTestPlan( TestPlan plan, TestDescriptor root )
+    {
+        TestIdentifier rootIdentifier = TestIdentifier.from( root );
+        plan.add( rootIdentifier );
+        return rootIdentifier;
+    }
+
     private static UniqueId newId()
     {
         return UniqueId.forEngine( "engine" );
diff --git a/surefire-providers/surefire-junit3/src/main/java/org/apache/maven/surefire/junit/JUnit3Provider.java b/surefire-providers/surefire-junit3/src/main/java/org/apache/maven/surefire/junit/JUnit3Provider.java
index b8c83e1..f7bb710 100644
--- a/surefire-providers/surefire-junit3/src/main/java/org/apache/maven/surefire/junit/JUnit3Provider.java
+++ b/surefire-providers/surefire-junit3/src/main/java/org/apache/maven/surefire/junit/JUnit3Provider.java
@@ -133,7 +133,7 @@ public class JUnit3Provider
                                  Map<String, String> systemProperties )
         throws TestSetFailedException
     {
-        SimpleReportEntry report = new SimpleReportEntry( getClass().getName(), testSet.getName(), systemProperties );
+        SimpleReportEntry report = new SimpleReportEntry( testSet.getName(), null, systemProperties );
 
         reporter.testSetStarting( report );
 
diff --git a/surefire-providers/surefire-junit3/src/main/java/org/apache/maven/surefire/junit/TestListenerInvocationHandler.java b/surefire-providers/surefire-junit3/src/main/java/org/apache/maven/surefire/junit/TestListenerInvocationHandler.java
index 78e78ad..e5d2232 100644
--- a/surefire-providers/surefire-junit3/src/main/java/org/apache/maven/surefire/junit/TestListenerInvocationHandler.java
+++ b/surefire-providers/surefire-junit3/src/main/java/org/apache/maven/surefire/junit/TestListenerInvocationHandler.java
@@ -20,14 +20,19 @@ package org.apache.maven.surefire.junit;
  */
 
 import java.lang.reflect.InvocationHandler;
-import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.util.HashSet;
 import java.util.Set;
+
 import org.apache.maven.surefire.report.LegacyPojoStackTraceWriter;
 import org.apache.maven.surefire.report.ReportEntry;
 import org.apache.maven.surefire.report.RunListener;
 import org.apache.maven.surefire.report.SimpleReportEntry;
+import org.apache.maven.surefire.report.StackTraceWriter;
+
+import static org.apache.maven.surefire.report.SimpleReportEntry.withException;
+import static org.apache.maven.surefire.util.internal.TestClassMethodNameUtils.extractClassName;
+import static org.apache.maven.surefire.util.internal.TestClassMethodNameUtils.extractMethodName;
 
 /**
  * Invocation Handler for TestListener proxies to delegate to our {@link RunListener}
@@ -149,25 +154,24 @@ public class TestListenerInvocationHandler
     // Handler for TestListener.startTest(Test)
     private void handleStartTest( Object[] args )
     {
-        ReportEntry report = new SimpleReportEntry( args[0].getClass().getName(), args[0].toString() );
+        ReportEntry report = createStartEndReportEntry( args );
 
         reporter.testStarting( report );
     }
 
     // Handler for TestListener.addFailure(Test, Throwable)
     private void handleAddError( Object[] args )
-        throws IllegalAccessException, InvocationTargetException
+        throws ReflectiveOperationException
     {
-        ReportEntry report = SimpleReportEntry.withException( args[0].getClass().getName(), args[0].toString(),
-                                                              getStackTraceWriter( args ) );
+        ReportEntry report = toReportEntryWithException( args );
 
         reporter.testError( report );
 
         failedTestsSet.add( new FailedTest( args[0], Thread.currentThread() ) );
     }
 
-    private LegacyPojoStackTraceWriter getStackTraceWriter( Object[] args )
-        throws IllegalAccessException, InvocationTargetException
+    private static LegacyPojoStackTraceWriter toStackTraceWriter( Object[] args )
+        throws ReflectiveOperationException
     {
         String testName;
 
@@ -185,10 +189,9 @@ public class TestListenerInvocationHandler
     }
 
     private void handleAddFailure( Object[] args )
-        throws IllegalAccessException, InvocationTargetException
+        throws ReflectiveOperationException
     {
-        ReportEntry report = SimpleReportEntry.withException( args[0].getClass().getName(), args[0].toString(),
-                                                              getStackTraceWriter( args ) );
+        ReportEntry report = toReportEntryWithException( args );
 
         reporter.testFailed( report );
 
@@ -201,9 +204,25 @@ public class TestListenerInvocationHandler
 
         if ( !testHadFailed )
         {
-            ReportEntry report = new SimpleReportEntry( args[0].getClass().getName(), args[0].toString() );
+            ReportEntry report = createStartEndReportEntry( args );
 
             reporter.testSucceeded( report );
         }
     }
+
+    private static ReportEntry toReportEntryWithException( Object[] args )
+            throws ReflectiveOperationException
+    {
+        String description = args[0].toString();
+        String className = extractClassName( description );
+        String methodName = extractMethodName( description );
+        StackTraceWriter stackTraceWriter = toStackTraceWriter( args );
+        return withException( className, methodName, stackTraceWriter );
+    }
+
+    private static SimpleReportEntry createStartEndReportEntry( Object[] args )
+    {
+        String description = args[0].toString();
+        return new SimpleReportEntry( extractClassName( description ), extractMethodName( description ) );
+    }
 }
diff --git a/surefire-providers/surefire-junit3/src/test/java/org/apache/maven/surefire/junit/JUnitTestSetTest.java b/surefire-providers/surefire-junit3/src/test/java/org/apache/maven/surefire/junit/JUnitTestSetTest.java
index 977ac9e..1381303 100644
--- a/surefire-providers/surefire-junit3/src/test/java/org/apache/maven/surefire/junit/JUnitTestSetTest.java
+++ b/surefire-providers/surefire-junit3/src/test/java/org/apache/maven/surefire/junit/JUnitTestSetTest.java
@@ -42,10 +42,12 @@ public class JUnitTestSetTest
         JUnitTestSet testSet = new JUnitTestSet( Suite.class, reflector );
         SuccessListener listener = new SuccessListener();
         testSet.execute( listener, testClassLoader );
-        List succeededTests = listener.getSucceededTests();
+        List<ReportEntry> succeededTests = listener.getSucceededTests();
         assertEquals( 1, succeededTests.size() );
-        assertEquals( "testSuccess(org.apache.maven.surefire.junit.JUnitTestSetTest$AlwaysSucceeds)",
-                      ( (ReportEntry) succeededTests.get( 0 ) ).getName() );
+        assertEquals( "org.apache.maven.surefire.junit.JUnitTestSetTest$AlwaysSucceeds",
+                succeededTests.get( 0 ).getSourceName() );
+        assertEquals( "testSuccess",
+                      succeededTests.get( 0 ).getName() );
     }
 
     public static final class AlwaysSucceeds
@@ -81,7 +83,7 @@ public class JUnitTestSetTest
         @Override
         public void testSucceeded( ReportEntry report )
         {
-            this.succeededTests.add( report );
+            succeededTests.add( report );
         }
 
         @Override
@@ -118,7 +120,7 @@ public class JUnitTestSetTest
             testSkipped( report );
         }
 
-        public List getSucceededTests()
+        List<ReportEntry> getSucceededTests()
         {
             return succeededTests;
         }
diff --git a/surefire-providers/surefire-junit4/src/main/java/org/apache/maven/surefire/junit4/JUnit4Provider.java b/surefire-providers/surefire-junit4/src/main/java/org/apache/maven/surefire/junit4/JUnit4Provider.java
index c31a019..f64b93d 100644
--- a/surefire-providers/surefire-junit4/src/main/java/org/apache/maven/surefire/junit4/JUnit4Provider.java
+++ b/surefire-providers/surefire-junit4/src/main/java/org/apache/maven/surefire/junit4/JUnit4Provider.java
@@ -231,7 +231,7 @@ public class JUnit4Provider
 
     private void executeTestSet( Class<?> clazz, RunListener reporter, Notifier notifier )
     {
-        final SimpleReportEntry report = new SimpleReportEntry( getClass().getName(), clazz.getName(), systemProps() );
+        final SimpleReportEntry report = new SimpleReportEntry( clazz.getName(), null, systemProps() );
         reporter.testSetStarting( report );
         try
         {
diff --git a/surefire-providers/surefire-junit4/src/main/java/org/apache/maven/surefire/junit4/TestResolverFilter.java b/surefire-providers/surefire-junit4/src/main/java/org/apache/maven/surefire/junit4/TestResolverFilter.java
index 4205b14..72669a8 100644
--- a/surefire-providers/surefire-junit4/src/main/java/org/apache/maven/surefire/junit4/TestResolverFilter.java
+++ b/surefire-providers/surefire-junit4/src/main/java/org/apache/maven/surefire/junit4/TestResolverFilter.java
@@ -1 +1 @@
-package org.apache.maven.surefire.junit4;

/*
 * 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.surefire.common.junit4.ClassMethod;
import org.apache.maven.surefire.testset.TestListResolver;
import org.junit.runner.
 Description;
import org.junit.runner.manipulation.Filter;

import static org.apache.maven.surefire.common.junit4.JUnit4ProviderUtil.cutTestClassAndMethod;
import static org.apache.maven.surefire.testset.TestListResolver.toClassFileName;

/**
 * Method filter used in {@link JUnit4Provider}.
 */
final class TestResolverFilter
    extends Filter
{
    private final TestListResolver methodFilter;

    TestResolverFilter( TestListResolver methodFilter )
    {
        this.methodFilter = methodFilter;
    }

    @Override
    public boolean shouldRun( Description description )
    {
        // class: Java class name; method: 1. "testMethod" or 2. "testMethod[5+whatever]" in @Parameterized
        final ClassMethod cm = cutTestClassAndMethod( description );
        final boolean isSuite = description.isSuite();
        final boolean isValidTest = description.isTest() && cm.isValid();
        final String clazz = cm.getClazz();
        final String method = cm.getMethod();
        return is
 Suite || isValidTest && methodFilter.shouldRun( toClassFileName( clazz ), method );
    }

    @Override
    public String describe()
    {
        return methodFilter.toString();
    }
}
\ No newline at end of file
+package org.apache.maven.surefire.junit4;

/*
 * 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.surefire.util.internal.ClassMethod;
import org.apache.maven.surefire.testset.TestListResolver;
import org.junit.runner.
 Description;
import org.junit.runner.manipulation.Filter;

import static org.apache.maven.surefire.common.junit4.JUnit4ProviderUtil.toClassMethod;
import static org.apache.maven.surefire.testset.TestListResolver.toClassFileName;

/**
 * Method filter used in {@link JUnit4Provider}.
 */
final class TestResolverFilter
    extends Filter
{
    private final TestListResolver methodFilter;

    TestResolverFilter( TestListResolver methodFilter )
    {
        this.methodFilter = methodFilter;
    }

    @Override
    public boolean shouldRun( Description description )
    {
        // class: Java class name; method: 1. "testMethod" or 2. "testMethod[5+whatever]" in @Parameterized
        final ClassMethod cm = toClassMethod( description );
        final boolean isSuite = description.isSuite();
        final boolean isValidTest = description.isTest() && cm.isValidTest();
        final String clazz = cm.getClazz();
        final String method = cm.getMethod();
        return isSuite || isV
 alidTest && methodFilter.shouldRun( toClassFileName( clazz ), method );
    }

    @Override
    public String describe()
    {
        return methodFilter.toString();
    }
}
\ No newline at end of file
diff --git a/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/JUnitCoreRunListener.java b/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/JUnitCoreRunListener.java
index ae00fdb..03e314e 100644
--- a/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/JUnitCoreRunListener.java
+++ b/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/JUnitCoreRunListener.java
@@ -20,7 +20,7 @@ package org.apache.maven.surefire.junitcore;
  */
 
 import org.apache.maven.surefire.common.junit4.JUnit4RunListener;
-import org.apache.maven.surefire.common.junit48.JUnit46StackTraceWriter;
+import org.apache.maven.surefire.common.junit4.JUnit4StackTraceWriter;
 import org.apache.maven.surefire.report.RunListener;
 import org.apache.maven.surefire.report.StackTraceWriter;
 import org.junit.runner.Description;
@@ -29,6 +29,8 @@ import org.junit.runner.notification.Failure;
 
 import java.util.Map;
 
+import static org.apache.maven.surefire.util.internal.TestClassMethodNameUtils.extractClassName;
+
 /**
  * Noteworthy things about JUnit4 listening:
  * <br>
@@ -95,7 +97,7 @@ public class JUnitCoreRunListener
     {
         if ( description.isTest() )
         {
-            final String testClassName = extractDescriptionClassName( description );
+            final String testClassName = extractClassName( description.getDisplayName() );
             if ( testClassName != null )
             {
                 final TestSet testSet;
@@ -121,18 +123,6 @@ public class JUnitCoreRunListener
     @Override
     protected StackTraceWriter createStackTraceWriter( Failure failure )
     {
-        return new JUnit46StackTraceWriter( failure );
-    }
-
-    @Override
-    protected String extractDescriptionClassName( Description description )
-    {
-        return description.getClassName();
-    }
-
-    @Override
-    protected String extractDescriptionMethodName( Description description )
-    {
-        return description.getMethodName();
+        return new JUnit4StackTraceWriter( failure );
     }
 }
diff --git a/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/NonConcurrentRunListener.java b/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/NonConcurrentRunListener.java
index f8d2fb7..71ec93d 100644
--- a/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/NonConcurrentRunListener.java
+++ b/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/NonConcurrentRunListener.java
@@ -19,6 +19,7 @@ package org.apache.maven.surefire.junitcore;
  * under the License.
  */
 
+import org.apache.maven.surefire.util.internal.ClassMethod;
 import org.apache.maven.surefire.common.junit4.JUnit4RunListener;
 import org.apache.maven.surefire.report.ConsoleOutputReceiver;
 import org.apache.maven.surefire.report.RunListener;
@@ -32,6 +33,7 @@ import org.junit.runner.notification.Failure;
 import java.util.Collections;
 import java.util.Map;
 
+import static org.apache.maven.surefire.common.junit4.JUnit4ProviderUtil.toClassMethod;
 import static org.apache.maven.surefire.util.internal.ObjectUtils.systemProps;
 
 /**
@@ -63,13 +65,14 @@ public class NonConcurrentRunListener
     @Override
     protected SimpleReportEntry createReportEntry( Description description )
     {
-        return new SimpleReportEntry( extractDescriptionClassName( description ), description.getDisplayName() );
+        ClassMethod classMethod = toClassMethod( description );
+        return new SimpleReportEntry( classMethod.getClazz(), classMethod.getMethod() );
     }
 
     private TestSetReportEntry createReportEntryForTestSet( Description description, Map<String, String> systemProps )
     {
-        String testClassName = extractDescriptionClassName( description );
-        return new SimpleReportEntry( testClassName, testClassName, systemProps );
+        ClassMethod classMethod = toClassMethod( description );
+        return new SimpleReportEntry( classMethod.getClazz(), classMethod.getClazz(), systemProps );
     }
 
     private TestSetReportEntry createTestSetReportEntryStarted( Description description )
@@ -83,18 +86,6 @@ public class NonConcurrentRunListener
     }
 
     @Override
-    protected String extractDescriptionClassName( Description description )
-    {
-        return description.getClassName();
-    }
-
-    @Override
-    protected String extractDescriptionMethodName( Description description )
-    {
-        return description.getMethodName();
-    }
-
-    @Override
     public void testStarted( Description description )
         throws Exception
     {
diff --git a/surefire-providers/surefire-junit47/src/test/java/org/apache/maven/surefire/junitcore/JUnitCoreRunListenerTest.java b/surefire-providers/surefire-junit47/src/test/java/org/apache/maven/surefire/junitcore/JUnitCoreRunListenerTest.java
index b467f63..08bbd2a 100644
--- a/surefire-providers/surefire-junit47/src/test/java/org/apache/maven/surefire/junitcore/JUnitCoreRunListenerTest.java
+++ b/surefire-providers/surefire-junit47/src/test/java/org/apache/maven/surefire/junitcore/JUnitCoreRunListenerTest.java
@@ -43,7 +43,6 @@ public class JUnitCoreRunListenerTest
     extends TestCase
 {
     public void testTestRunStarted()
-        throws Exception
     {
         RunListener jUnit4TestSetReporter =
             new JUnitCoreRunListener( new MockReporter(), new HashMap<String, TestSet>() );
@@ -55,7 +54,6 @@ public class JUnitCoreRunListenerTest
     }
 
     public void testFailedAssumption()
-        throws Exception
     {
         RunListener jUnit4TestSetReporter =
             new JUnitCoreRunListener( new MockReporter(), new HashMap<String, TestSet>() );
diff --git a/surefire-providers/surefire-testng/src/main/java/org/apache/maven/surefire/testng/TestNGReporter.java b/surefire-providers/surefire-testng/src/main/java/org/apache/maven/surefire/testng/TestNGReporter.java
index 19cd22d..8cb7641 100644
--- a/surefire-providers/surefire-testng/src/main/java/org/apache/maven/surefire/testng/TestNGReporter.java
+++ b/surefire-providers/surefire-testng/src/main/java/org/apache/maven/surefire/testng/TestNGReporter.java
@@ -25,6 +25,7 @@ import org.apache.maven.surefire.report.ReportEntry;
 import org.apache.maven.surefire.report.RunListener;
 import org.apache.maven.surefire.report.SimpleReportEntry;
 
+import org.testng.IClass;
 import org.testng.ISuite;
 import org.testng.ISuiteListener;
 import org.testng.ITestContext;
@@ -64,54 +65,45 @@ public class TestNGReporter
     @Override
     public void onTestStart( ITestResult result )
     {
-        String group = groupString( result.getMethod().getGroups(), result.getTestClass().getName() );
-        String userFriendlyTestName = getUserFriendlyTestName( result );
-        reporter.testStarting( new CategorizedReportEntry( getSource( result ), userFriendlyTestName, group ) );
-    }
-
-    private String getSource( ITestResult result )
-    {
-        return result.getTestClass().getName();
+        String clazz = result.getTestClass().getName();
+        String group = groupString( result.getMethod().getGroups(), clazz );
+        reporter.testStarting( new CategorizedReportEntry( clazz, result.getName(), group ) );
     }
 
     @Override
     public void onTestSuccess( ITestResult result )
     {
-        ReportEntry report = new SimpleReportEntry( getSource( result ), getUserFriendlyTestName( result ) );
+        ReportEntry report = new SimpleReportEntry( result.getTestClass().getName(), result.getName() );
         reporter.testSucceeded( report );
     }
 
     @Override
     public void onTestFailure( ITestResult result )
     {
-        ReportEntry report = withException( getSource( result ), getUserFriendlyTestName( result ),
-                new PojoStackTraceWriter( result.getTestClass().getRealClass().getName(),
+        IClass clazz = result.getTestClass();
+        ReportEntry report = withException( clazz.getName(), result.getName(),
+                new PojoStackTraceWriter( clazz.getRealClass().getName(),
                         result.getMethod().getMethodName(),
                         result.getThrowable() ) );
 
         reporter.testFailed( report );
     }
 
-    private static String getUserFriendlyTestName( ITestResult result )
-    {
-        // This is consistent with the JUnit output
-        return result.getName() + "(" + result.getTestClass().getName() + ")";
-    }
-
     @Override
     public void onTestSkipped( ITestResult result )
     {
         Throwable t = result.getThrowable();
         String reason = t == null ? null : t.getMessage();
-        ReportEntry report = ignored( getSource( result ), getUserFriendlyTestName( result ), reason );
+        ReportEntry report = ignored( result.getTestClass().getName(), result.getName(), reason );
         reporter.testSkipped( report );
     }
 
     @Override
     public void onTestFailedButWithinSuccessPercentage( ITestResult result )
     {
-        ReportEntry report = withException( getSource( result ), getUserFriendlyTestName( result ),
-                new PojoStackTraceWriter( result.getTestClass().getRealClass().getName(),
+        IClass clazz = result.getTestClass();
+        ReportEntry report = withException( clazz.getName(), result.getName(),
+                new PojoStackTraceWriter( clazz.getRealClass().getName(),
                         result.getMethod().getMethodName(),
                         result.getThrowable() ) );
 
diff --git a/surefire-providers/surefire-testng/src/main/java/org/apache/maven/surefire/testng/TestSuite.java b/surefire-providers/surefire-testng/src/main/java/org/apache/maven/surefire/testng/TestSuite.java
index ca40f7c..e9b0424 100644
--- a/surefire-providers/surefire-testng/src/main/java/org/apache/maven/surefire/testng/TestSuite.java
+++ b/surefire-providers/surefire-testng/src/main/java/org/apache/maven/surefire/testng/TestSuite.java
@@ -43,7 +43,7 @@ abstract class TestSuite
 
     final void startTestSuite( RunListener reporterManager )
     {
-        TestSetReportEntry report = new SimpleReportEntry( getClass().getName(), getSuiteName(), systemProps() );
+        TestSetReportEntry report = new SimpleReportEntry( getSuiteName(), null, systemProps() );
 
         try
         {
@@ -57,7 +57,7 @@ abstract class TestSuite
 
     final void finishTestSuite( RunListener reporterManager )
     {
-        SimpleReportEntry report = new SimpleReportEntry( getClass().getName(), getSuiteName(), systemProps() );
+        SimpleReportEntry report = new SimpleReportEntry( getSuiteName(), null, systemProps() );
         reporterManager.testSetCompleted( report );
     }
 }
diff --git a/surefire-report-parser/src/main/java/org/apache/maven/plugins/surefire/report/SurefireReportParser.java b/surefire-report-parser/src/main/java/org/apache/maven/plugins/surefire/report/SurefireReportParser.java
index da1b255..f6e644f 100644
--- a/surefire-report-parser/src/main/java/org/apache/maven/plugins/surefire/report/SurefireReportParser.java
+++ b/surefire-report-parser/src/main/java/org/apache/maven/plugins/surefire/report/SurefireReportParser.java
@@ -33,11 +33,10 @@ import javax.xml.parsers.ParserConfigurationException;
 
 import org.apache.maven.plugin.surefire.log.api.ConsoleLogger;
 import org.apache.maven.reporting.MavenReportException;
-import org.apache.maven.shared.utils.StringUtils;
 import org.apache.maven.shared.utils.io.DirectoryScanner;
 import org.xml.sax.SAXException;
 
-import static java.util.Collections.singletonList;
+import static org.apache.maven.shared.utils.StringUtils.split;
 
 /**
  *
@@ -57,7 +56,7 @@ public final class SurefireReportParser
 
     private final ConsoleLogger consoleLogger;
 
-    private List<File> reportsDirectories;
+    private final List<File> reportsDirectories;
 
     public SurefireReportParser( List<File> reportsDirectories, Locale locale, ConsoleLogger consoleLogger )
     {
@@ -104,21 +103,6 @@ public final class SurefireReportParser
         return testSuites;
     }
 
-    protected String parseTestSuiteName( String lineString )
-    {
-        return lineString.substring( lineString.lastIndexOf( "." ) + 1, lineString.length() );
-    }
-
-    protected String parseTestSuitePackageName( String lineString )
-    {
-        return lineString.substring( lineString.indexOf( ":" ) + 2, lineString.lastIndexOf( "." ) );
-    }
-
-    protected String parseTestCaseName( String lineString )
-    {
-        return lineString.substring( 0, lineString.indexOf( "(" ) );
-    }
-
     public Map<String, String> getSummary( List<ReportTestSuite> suites )
     {
         Map<String, String> totalSummary = new HashMap<>();
@@ -164,11 +148,6 @@ public final class SurefireReportParser
         return totalSummary;
     }
 
-    public void setReportsDirectory( File reportsDirectory )
-    {
-        reportsDirectories = singletonList( reportsDirectory );
-    }
-
     public NumberFormat getNumberFormat()
     {
         return numberFormat;
@@ -238,9 +217,9 @@ public final class SurefireReportParser
 
         scanner.setBasedir( directory );
 
-        scanner.setIncludes( StringUtils.split( includes, "," ) );
+        scanner.setIncludes( split( includes, "," ) );
 
-        scanner.setExcludes( StringUtils.split( excludes, "," ) );
+        scanner.setExcludes( split( excludes, "," ) );
 
         scanner.scan();
 
diff --git a/surefire-report-parser/src/test/java/org/apache/maven/plugins/surefire/report/SurefireReportParserTest.java b/surefire-report-parser/src/test/java/org/apache/maven/plugins/surefire/report/SurefireReportParserTest.java
index 870cd92..7176c4d 100644
--- a/surefire-report-parser/src/test/java/org/apache/maven/plugins/surefire/report/SurefireReportParserTest.java
+++ b/surefire-report-parser/src/test/java/org/apache/maven/plugins/surefire/report/SurefireReportParserTest.java
@@ -29,10 +29,10 @@ import java.util.List;
 import java.util.Map;
 
 import org.apache.maven.plugin.surefire.log.api.NullConsoleLogger;
-import org.apache.maven.reporting.MavenReportException;
 
 import junit.framework.TestCase;
 
+import static java.util.Collections.singletonList;
 import static java.util.Locale.ENGLISH;
 
 /**
@@ -41,23 +41,11 @@ import static java.util.Locale.ENGLISH;
 public class SurefireReportParserTest
     extends TestCase
 {
-    private SurefireReportParser report;
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    protected void setUp()
-        throws Exception
-    {
-        super.setUp();
-        report = new SurefireReportParser( null, ENGLISH, new NullConsoleLogger() );
-    }
-
     public void testParseXMLReportFiles()
-        throws MavenReportException, UnsupportedEncodingException
+        throws Exception
     {
-        report.setReportsDirectory( getTestDir() );
+        SurefireReportParser report =
+                new SurefireReportParser( singletonList( getTestDir() ), ENGLISH, new NullConsoleLogger() );
 
         List<ReportTestSuite> suites = report.parseXMLReportFiles();
 
@@ -79,21 +67,6 @@ public class SurefireReportParserTest
         return new File( URLDecoder.decode( resource.getPath(), "UTF-8" ) ).getAbsoluteFile();
     }
 
-    public void testParseTestSuiteName()
-    {
-        assertEquals( "CircleTest", report.parseTestSuiteName( "Battery: com.shape.CircleTest" ) );
-    }
-
-    public void testParseTestSuitePackageName()
-    {
-        assertEquals( "com.shape", report.parseTestSuitePackageName( "Battery: com.shape.CircleTest" ) );
-    }
-
-    public void testParseTestCaseName()
-    {
-        assertEquals( "testCase", report.parseTestCaseName( "testCase(com.shape.CircleTest)" ) );
-    }
-
     public void testGetSummary()
         throws Exception
     {
@@ -117,6 +90,8 @@ public class SurefireReportParserTest
 
         suites.add( tSuite2 );
 
+        SurefireReportParser report = new SurefireReportParser( null, ENGLISH, new NullConsoleLogger() );
+
         Map<String, String> testMap = report.getSummary( suites );
 
         assertEquals( 20, Integer.parseInt( testMap.get( "totalErrors" ) ) );
@@ -156,6 +131,8 @@ public class SurefireReportParserTest
 
         suites.add( tSuite3 );
 
+        SurefireReportParser report = new SurefireReportParser( null, ENGLISH, new NullConsoleLogger() );
+
         Map<String, List<ReportTestSuite>> groupMap = report.getSuitesGroupByPackage( suites );
 
         assertEquals( 2, groupMap.size() );
@@ -170,6 +147,7 @@ public class SurefireReportParserTest
     public void testComputePercentage()
         throws Exception
     {
+        SurefireReportParser report = new SurefireReportParser( null, ENGLISH, new NullConsoleLogger() );
         NumberFormat numberFormat = report.getNumberFormat();
 
         assertEquals( 70.00f, numberFormat.parse( report.computePercentage( 100, 20, 10, 0 ) ).floatValue(), 0 );
@@ -211,6 +189,8 @@ public class SurefireReportParserTest
 
         suites.add( tSuite2 );
 
+        SurefireReportParser report = new SurefireReportParser( null, ENGLISH, new NullConsoleLogger() );
+
         List<ReportTestCase> failures = report.getFailureDetails( suites );
 
         assertEquals( 2, failures.size() );
diff --git a/surefire-report-parser/src/test/resources/test-reports/com.shape.CircleTest.txt b/surefire-report-parser/src/test/resources/test-reports/com.shape.CircleTest.txt
index 5030dee..0e2ee04 100644
--- a/surefire-report-parser/src/test/resources/test-reports/com.shape.CircleTest.txt
+++ b/surefire-report-parser/src/test/resources/test-reports/com.shape.CircleTest.txt
@@ -1,10 +1,10 @@
 -------------------------------------------------------------------------------
 Battery: com.shape.CircleTest
 -------------------------------------------------------------------------------
-testX(com.shape.CircleTest)
-testY(com.shape.CircleTest)
-testXY(com.shape.CircleTest)
-testRadius(com.shape.CircleTest)
+com.shape.CircleTest.testX
+com.shape.CircleTest.testY
+com.shape.CircleTest.testXY
+com.shape.CircleTest.testRadius
 
 [ stdout ] ---------------------------------------------------------------
 
@@ -63,7 +63,7 @@ junit.framework.AssertionFailedError: expected:<20> but was:<10>
 	at org.codehaus.classworlds.Launcher.launch(Launcher.java:255)
 	at org.codehaus.classworlds.Launcher.mainWithExitCode(Launcher.java:430)
 	at org.codehaus.classworlds.Launcher.main(Launcher.java:375)
-testProperties(com.shape.CircleTest)
+com.shape.CircleTest.testProperties
 
 [ stdout ] ---------------------------------------------------------------
 
@@ -117,6 +117,6 @@ java.lang.ArithmeticException: / by zero
 	at org.codehaus.classworlds.Launcher.launch(Launcher.java:255)
 	at org.codehaus.classworlds.Launcher.mainWithExitCode(Launcher.java:430)
 	at org.codehaus.classworlds.Launcher.main(Launcher.java:375)
-testPI(com.shape.CircleTest)
-testCircumference(com.shape.CircleTest)
-testDiameter(com.shape.CircleTest)
+com.shape.CircleTest.testPI
+com.shape.CircleTest.testCircumference
+com.shape.CircleTest.testDiameter
diff --git a/surefire-report-parser/src/test/resources/test-reports/com.shapeclone.CircleTest.txt b/surefire-report-parser/src/test/resources/test-reports/com.shapeclone.CircleTest.txt
index 90e3239..e190044 100644
--- a/surefire-report-parser/src/test/resources/test-reports/com.shapeclone.CircleTest.txt
+++ b/surefire-report-parser/src/test/resources/test-reports/com.shapeclone.CircleTest.txt
@@ -1,10 +1,10 @@
 -------------------------------------------------------------------------------
 Battery: com.shapeclone.CircleTest
 -------------------------------------------------------------------------------
-testX(com.shapeclone.CircleTest)
-testY(com.shapeclone.CircleTest)
-testXY(com.shapeclone.CircleTest)
-testRadius(com.shapeclone.CircleTest)
+com.shapeclone.CircleTest.testX
+com.shapeclone.CircleTest.testY
+com.shapeclone.CircleTest.testXY
+com.shapeclone.CircleTest.testRadius
 
 [ stdout ] ---------------------------------------------------------------
 
@@ -63,7 +63,7 @@ junit.framework.AssertionFailedError: expected:<20> but was:<10>
 	at org.codehaus.classworlds.Launcher.launch(Launcher.java:255)
 	at org.codehaus.classworlds.Launcher.mainWithExitCode(Launcher.java:430)
 	at org.codehaus.classworlds.Launcher.main(Launcher.java:375)
-testProperties(com.shapeclone.CircleTest)
+com.shapeclone.CircleTest.testProperties
 
 [ stdout ] ---------------------------------------------------------------
 
@@ -117,6 +117,6 @@ java.lang.ArithmeticException: / by zero
 	at org.codehaus.classworlds.Launcher.launch(Launcher.java:255)
 	at org.codehaus.classworlds.Launcher.mainWithExitCode(Launcher.java:430)
 	at org.codehaus.classworlds.Launcher.main(Launcher.java:375)
-testPI(com.shapeclone.CircleTest)
-testCircumference(com.shapeclone.CircleTest)
-testDiameter(com.shapeclone.CircleTest)
+com.shapeclone.CircleTest.testPI
+com.shapeclone.CircleTest.testCircumference
+com.shapeclone.CircleTest.testDiameter