[maven-surefire] branch junit5-displayname created (now ff871c8)

classic Classic list List threaded Threaded
2 messages Options
Reply | Threaded
Open this post in threaded view
|

[maven-surefire] branch junit5-displayname created (now ff871c8)

Tibor Digana
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.


      at ff871c8  junit5-displayname

This branch includes the following new commits:

     new ff871c8  junit5-displayname

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.


Reply | Threaded
Open this post in threaded view
|

[maven-surefire] 01/01: junit5-displayname

Tibor Digana
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 ff871c85dab97cd382190b89a123664c178d1697
Author: tibordigana <[hidden email]>
AuthorDate: Sat Jan 5 15:48:30 2019 +0100

    junit5-displayname
---
 .../plugin/surefire/report/WrappedReportEntry.java |   9 +-
 .../surefire/runorder/StatisticsReporter.java      |   5 +-
 .../surefire/report/WrappedReportEntryTest.java    |  14 +-
 .../runorder/RunEntryStatisticsMapTest.java        | 128 ++++++++-
 pom.xml                                            |   4 +-
 .../surefire/runorder/RunEntryStatistics.java      |  47 +---
 .../surefire/runorder/RunEntryStatisticsMap.java   | 172 ++++++++-----
 .../apache/maven/surefire/report/ReportEntry.java  |   8 +
 .../maven/surefire/report/SimpleReportEntry.java   |   6 +
 .../maven/surefire/util/internal}/ClassMethod.java |  32 ++-
 .../util/internal/TestClassMethodNameUtils.java    |  32 ++-
 .../runorder/ThreadedExecutionSchedulerTest.java   |  26 +-
 surefire-its/pom.xml                               |   2 +-
 .../maven/surefire/its/JUnitPlatformEnginesIT.java |   8 +-
 .../surefire/report/PojoStackTraceWriter.java      |  24 ++
 .../surefire/common/junit4/JUnit4ProviderUtil.java |  38 +--
 .../surefire/common/junit4/JUnit4RunListener.java  |  48 +---
 .../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 | 286 +++++++++------------
 .../surefire/junitplatform/JUnit47SuiteTest.java}  |  45 ++--
 .../junitplatform/JUnitPlatformProviderTest.java   |   8 +-
 .../junitplatform/RunListenerAdapterTest.java      | 124 +++++----
 .../maven/surefire/junit/JUnitTestSetTest.java     |   8 +-
 .../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 +--
 .../surefire/report/SurefireReportParser.java      |  29 +--
 .../surefire/report/SurefireReportParserTest.java  |  42 +--
 34 files changed, 677 insertions(+), 651 deletions(-)

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..ba11bbc 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
@@ -74,6 +74,12 @@ public class WrappedReportEntry
         return elapsed;
     }
 
+    @Override
+    public int getElapsed( int fallback )
+    {
+        return elapsed == null ? fallback : elapsed;
+    }
+
     public ReportEntryType getReportEntryType()
     {
         return reportEntryType;
@@ -137,8 +143,7 @@ public class WrappedReportEntry
 
     public String getReportName()
     {
-        final int i = getName().lastIndexOf( "(" );
-        return i > 0 ? getName().substring( 0, i ) : getName();
+        return getName();
     }
 
     public String getReportName( String suffix )
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/WrappedReportEntryTest.java b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/report/WrappedReportEntryTest.java
index 030fc2f..f499ec3 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,9 +29,7 @@ import junit.framework.TestCase;
 public class WrappedReportEntryTest
     extends TestCase
 {
-
     public void testClassNameOnly()
-        throws Exception
     {
         String category = "surefire.testcase.JunitParamsTest";
         WrappedReportEntry wr =
@@ -42,16 +40,15 @@ public class WrappedReportEntryTest
 
     public void testRegular()
     {
-        ReportEntry reportEntry = new SimpleReportEntry( "fud", "testSum(surefire.testcase.NonJunitParamsTest)" );
+        ReportEntry reportEntry = new SimpleReportEntry( "fud", "testSum" );
         WrappedReportEntry wr = new WrappedReportEntry( reportEntry, null, 12, null, null );
         final String reportName = wr.getReportName();
         assertEquals( "testSum", reportName );
     }
 
     public void testGetReportNameWithParams()
-        throws Exception
     {
-        String category = "[0] 1\u002C 2\u002C 3 (testSum)(surefire.testcase.JunitParamsTest)";
+        String category = "[0] 1\u002C 2\u002C 3 (testSum)";
         ReportEntry reportEntry = new SimpleReportEntry( "fud", category );
         WrappedReportEntry wr = new WrappedReportEntry( reportEntry, null, 12, null, null );
         final String reportName = wr.getReportName();
@@ -59,15 +56,12 @@ public class WrappedReportEntryTest
     }
 
     public void testElapsed()
-        throws Exception
     {
-        String category = "[0] 1\u002C 2\u002C 3 (testSum)(surefire.testcase.JunitParamsTest)";
+        String category = "[0] 1\u002C 2\u002C 3 (testSum)";
         ReportEntry reportEntry = new SimpleReportEntry( "fud", category );
         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..42698d7 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
@@ -20,15 +20,23 @@ package org.apache.maven.plugin.surefire.runorder;
  */
 
 import java.io.File;
+import java.io.FileInputStream;
 import java.io.IOException;
-import java.io.StringReader;
+import java.io.InputStream;
+import java.io.StringBufferInputStream;
 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 StringBufferInputStream( content );
     }
 
     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 72b9b5a..a048c46 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/report/ReportEntry.java b/surefire-api/src/main/java/org/apache/maven/surefire/report/ReportEntry.java
index ec0f782..e0f3468 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.
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..4172513 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
@@ -167,6 +167,12 @@ 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="
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:[hidden email]">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..d08d4bf 100644
--- a/surefire-its/pom.xml
+++ b/surefire-its/pom.xml
@@ -169,7 +169,7 @@
                     <forkMode>once</forkMode>
                     <argLine>-server -Xmx64m -XX:+UseG1GC -XX:+TieredCompilation -XX:TieredStopAtLevel=1 -Djava.awt.headless=true -Djdk.net.URLClassPath.disableClassPathURLCheck=true</argLine>
                     <includes>
-                        <include>org/apache/**/*IT*.java</include>
+                        <include>org/apache/**/*Platform*IT*.java</include>
                     </includes>
                     <!-- Pass current surefire version to the main suite so that it -->
                     <!-- can forward to all integration test projects. SUREFIRE-513 -->
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-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/JUnit4RunListener.java b/surefire-providers/common-junit4/src/main/java/org/apache/maven/surefire/common/junit4/JUnit4RunListener.java
index 7ed2ad9..dc98fa9 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 ) );
     }
 
     /**
@@ -114,10 +115,10 @@ public class JUnit4RunListener
                 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(), testHeader, stackTrace );
 
             if ( failure.getException() instanceof AssertionError )
             {
@@ -140,8 +141,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 +175,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 +182,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 85227f3..ce80643 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,17 +20,15 @@ package org.apache.maven.surefire.junitplatform;
  */
 
 import static org.apache.maven.surefire.report.SimpleReportEntry.ignored;
-import static org.junit.platform.engine.TestExecutionResult.Status.ABORTED;
-import static org.junit.platform.engine.TestExecutionResult.Status.FAILED;
+import static org.apache.maven.surefire.report.SimpleReportEntry.withException;
 
 import java.util.Optional;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
 
 import org.apache.maven.surefire.report.PojoStackTraceWriter;
 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.platform.engine.TestExecutionResult;
 import org.junit.platform.engine.TestSource;
 import org.junit.platform.engine.support.descriptor.ClassSource;
@@ -38,7 +36,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
@@ -46,12 +43,9 @@ import org.junit.platform.launcher.listeners.LegacyReportingUtils;
 final class RunListenerAdapter
     implements TestExecutionListener
 {
-
     private final RunListener runListener;
 
-    private TestPlan testPlan;
-
-    private Set<TestIdentifier> testSetNodes = ConcurrentHashMap.newKeySet();
+    private volatile TestPlan testPlan;
 
     RunListenerAdapter( RunListener runListener )
     {
@@ -61,13 +55,13 @@ 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;
     }
 
     @Override
@@ -76,117 +70,82 @@ final class RunListenerAdapter
         if ( testIdentifier.isContainer()
                         && testIdentifier.getSource().filter( ClassSource.class::isInstance ).isPresent() )
         {
-            startTestSetIfPossible( testIdentifier );
+            runListener.testSetStarting( createTestSetReportEntry( testIdentifier ) );
         }
-        if ( testIdentifier.isTest() )
+        else 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 );
-        }
-        else if ( testIdentifier.isTest() )
-        {
-            runListener.testSucceeded( createReportEntry( 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 );
+    public void executionFinished( TestIdentifier testIdentifier, TestExecutionResult testExecutionResult )
+    {
+        boolean isClass = testIdentifier.isContainer()
+                && testIdentifier.getSource().filter( ClassSource.class::isInstance ).isPresent();
+
+        boolean isTest = testIdentifier.isTest();
+
+        if ( isClass || isTest )
+        {
+            switch ( testExecutionResult.getStatus() )
+            {
+                case ABORTED:
+                    TestSetReportEntry reportEntry = createReportEntry( testIdentifier, testExecutionResult );
+                    if ( isTest )
+                    {
+                        runListener.testAssumptionFailure( reportEntry );
+                    }
+                    else
+                    {
+                        runListener.testSetCompleted( reportEntry );
+                    }
+                    break;
+                case FAILED:
+                    reportEntry = createReportEntry( testIdentifier, testExecutionResult );
+                    if ( !isTest )
+                    {
+                        runListener.testSetCompleted( reportEntry );
+                    }
+                    else if ( testExecutionResult.getThrowable()
+                            .filter( AssertionError.class::isInstance ).isPresent() )
+                    {
+                        runListener.testFailed( reportEntry );
+                    }
+                    else
+                    {
+                        runListener.testError( reportEntry );
+                    }
+                    break;
+                default:
+                    reportEntry = createReportEntry( testIdentifier );
+                    if ( isTest )
+                    {
+                        runListener.testSucceeded( reportEntry );
+                    }
+                    else
+                    {
+                        runListener.testSetCompleted( reportEntry );
+                    }
+            }
         }
     }
 
-    private boolean isTestSetStarted( TestIdentifier testIdentifier )
-    {
-        return testSetNodes.contains( testIdentifier )
-                        || testPlan.getParent( testIdentifier ).map( this::isTestSetStarted ).orElse( false );
-    }
-
-    private void startTestSetIfPossible( TestIdentifier testIdentifier )
-    {
-        if ( !isTestSetStarted( testIdentifier ) )
-        {
-            startTestSet( testIdentifier );
-        }
-    }
-
-    private void completeTestSetIfNecessary( TestIdentifier testIdentifier )
-    {
-        if ( testSetNodes.contains( testIdentifier ) )
-        {
-            completeTestSet( testIdentifier );
-        }
-    }
-
-    private void startTestSet( TestIdentifier testIdentifier )
-    {
-        runListener.testSetStarting( createTestSetReportEntry( testIdentifier ) );
-        testSetNodes.add( testIdentifier );
-    }
-
-    private void completeTestSet( TestIdentifier testIdentifier )
+    @Override
+    public void executionSkipped( TestIdentifier testIdentifier, String reason )
     {
-        runListener.testSetCompleted( createTestSetReportEntry( testIdentifier ) );
-        testSetNodes.remove( testIdentifier );
-    }
-
-    private void reportFailedTest(
-                    TestIdentifier testIdentifier, TestExecutionResult testExecutionResult )
-    {
-        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[0];
+        String methodName = classMethodName[1];
+        runListener.testSkipped( ignored( className, methodName, reason ) );
     }
 
     private SimpleReportEntry createTestSetReportEntry( TestIdentifier testIdentifier )
     {
-        return new SimpleReportEntry(
-                        JUnitPlatformProvider.class.getName(), testIdentifier.getLegacyReportingName() );
+        String[] classMethodName = toClassMethodName( testIdentifier );
+        String className = classMethodName[0];
+        String methodName = classMethodName[1];
+        return new SimpleReportEntry( className, methodName );
     }
 
     private SimpleReportEntry createReportEntry( TestIdentifier testIdentifier )
@@ -194,79 +153,88 @@ final class RunListenerAdapter
         return createReportEntry( testIdentifier, (StackTraceWriter) null );
     }
 
-    private SimpleReportEntry createReportEntry(
-                    TestIdentifier testIdentifier, TestExecutionResult testExecutionResult )
-    {
-        return createReportEntry(
-                        testIdentifier, getStackTraceWriter( testIdentifier, testExecutionResult ) );
-    }
-
-    private SimpleReportEntry createReportEntry(
-                    TestIdentifier testIdentifier, StackTraceWriter stackTraceWriter )
-    {
-        String source = getLegacyReportingClassName( testIdentifier );
-        String name = getLegacyReportingName( testIdentifier );
-
-        return SimpleReportEntry.withException( source, name, stackTraceWriter );
-    }
-
-    private String getLegacyReportingName( TestIdentifier testIdentifier )
+    private SimpleReportEntry createReportEntry( TestIdentifier testIdentifier,
+                                                 TestExecutionResult testExecutionResult )
     {
-        // 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( ')', '}' );
+        return createReportEntry( testIdentifier, toStackTraceWriter( testIdentifier, testExecutionResult ) );
     }
 
-    private String getLegacyReportingClassName( TestIdentifier testIdentifier )
+    private SimpleReportEntry createReportEntry( TestIdentifier testIdentifier, StackTraceWriter stackTraceWriter )
     {
-        return LegacyReportingUtils.getClassName( testPlan, testIdentifier );
+        String[] classMethodName = toClassMethodName( testIdentifier );
+        String className = classMethodName[0];
+        String methodName = classMethodName[1];
+        return withException( className, methodName, stackTraceWriter );
     }
 
-    private StackTraceWriter getStackTraceWriter(
-                    TestIdentifier testIdentifier, TestExecutionResult testExecutionResult )
+    private StackTraceWriter toStackTraceWriter( 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
+                return toStackTraceWriter( testIdentifier, testExecutionResult.getThrowable().orElse( null ) );
+            default:
+                return testExecutionResult.getThrowable().map( t -> toStackTraceWriter( testIdentifier, t ) )
+                        .orElse( null );
         }
-        return throwable.map( t -> getStackTraceWriter( testIdentifier, t ) ).orElse( null );
     }
 
-    private StackTraceWriter getStackTraceWriter( TestIdentifier testIdentifier, Throwable throwable )
+    private StackTraceWriter toStackTraceWriter( TestIdentifier testIdentifier, Throwable throwable )
     {
-        String className = getClassName( testIdentifier );
-        String methodName = getMethodName( testIdentifier ).orElse( "" );
+        String[] classMethodName = toClassMethodName( testIdentifier );
+        String className = classMethodName[0];
+        String methodName = classMethodName[1];
         return new PojoStackTraceWriter( className, methodName, 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 source = testPlan.getParent( testIdentifier )
+                    .map( this::toClassMethodName )
+                    .map( s -> s[0] )
+                    .orElse( methodSource.getClassName() );
+
+            String method = methodSource.getMethodName();
+            boolean useMethod = display.equals( method ) || display.equals( method + "()" );
+            String name = useMethod ? method : display;
+
+            return new String[] { source, name };
         }
-        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 };
         }
-        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, 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..7aa8011 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
@@ -167,25 +167,25 @@ public class JUnitPlatformProviderTest
                         .verify( runListener )
                         .testSetStarting(
                                         new SimpleReportEntry(
-                                                        JUnitPlatformProvider.class.getName(),
+                                                TestClass1.class.getName(),
                                                         TestClass1.class.getName() ) );
         inOrder
                         .verify( runListener )
                         .testSetCompleted(
                                         new SimpleReportEntry(
-                                                        JUnitPlatformProvider.class.getName(),
+                                                TestClass1.class.getName(),
                                                         TestClass1.class.getName() ) );
         inOrder
                         .verify( runListener )
                         .testSetStarting(
                                         new SimpleReportEntry(
-                                                        JUnitPlatformProvider.class.getName(),
+                                                TestClass2.class.getName(),
                                                         TestClass2.class.getName() ) );
         inOrder
                         .verify( runListener )
                         .testSetCompleted(
                                         new SimpleReportEntry(
-                                                        JUnitPlatformProvider.class.getName(),
+                                                TestClass2.class.getName(),
                                                         TestClass2.class.getName() ) );
 
         assertThat( executionListener.summaries ).hasSize( 1 );
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..73f108c 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,15 +22,18 @@ 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.ArgumentMatchers.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
@@ -38,11 +41,15 @@ import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.verifyZeroInteractions;
 import static org.mockito.Mockito.when;
 
+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 +58,16 @@ 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 +76,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 +127,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,7 +146,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(),
+        verify( listener ).testSetStarting( new SimpleReportEntry( MyTestClass.class.getName(),
                                                         MyTestClass.class.getName() ) );
         verifyNoMoreInteractions( listener );
 
@@ -152,7 +159,7 @@ public class RunListenerAdapterTest
         verifyNoMoreInteractions( listener );
 
         adapter.executionFinished( TestIdentifier.from( parent ), successful() );
-        verify( listener ).testSetCompleted( new SimpleReportEntry( JUnitPlatformProvider.class.getName(),
+        verify( listener ).testSetCompleted( new SimpleReportEntry( MyTestClass.class.getName(),
                                                         MyTestClass.class.getName() ) );
         verifyNoMoreInteractions( listener );
 
@@ -161,11 +168,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 );
@@ -176,14 +182,12 @@ public class RunListenerAdapterTest
         adapter.testPlanExecutionStarted( plan );
         adapter.executionStarted( TestIdentifier.from( engine ) );
         adapter.executionStarted( TestIdentifier.from( parent ) );
+        verify( listener ).testSetStarting( new SimpleReportEntry( "parent", "parent" ) );
         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();
+        verify( listener ).testStarting( new SimpleReportEntry( "parent", "child1" ) );
+        verifyNoMoreInteractions( listener );
 
         adapter.executionFinished( TestIdentifier.from( child1 ), successful() );
         verify( listener ).testSucceeded( new SimpleReportEntry( "parent", "child1" ) );
@@ -198,8 +202,7 @@ public class RunListenerAdapterTest
         verifyNoMoreInteractions( listener );
 
         adapter.executionFinished( TestIdentifier.from( parent ), successful() );
-        verify( listener )
-                        .testSetCompleted( new SimpleReportEntry( JUnitPlatformProvider.class.getName(), "parent" ) );
+        verify( listener ).testSetCompleted( new SimpleReportEntry( "parent", "parent" ) );
         verifyNoMoreInteractions( listener );
 
         adapter.executionFinished( TestIdentifier.from( engine ), successful() );
@@ -207,7 +210,7 @@ public class RunListenerAdapterTest
     }
 
     @Test
-    public void notifiedForTestSetForSingleNodeEngine()
+    public void notifiedForUnclassifiedTestIdentifier()
     {
         EngineDescriptor engine = new EngineDescriptor( UniqueId.forEngine( "engine" ), "engine" )
         {
@@ -221,18 +224,12 @@ 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();
+        verify( listener ).testSucceeded( new SimpleReportEntry( "engine", "engine" ) );
+        verifyNoMoreInteractions( listener );
     }
 
     @Test
@@ -279,48 +276,54 @@ 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 name = MyTestClass.class.getName();
+        StackTraceWriter stw = new PojoStackTraceWriter( name, name, t );
+        verify( listener ).testSetCompleted( eq( new SimpleReportEntry( name, name, stw, null ) ) );
     }
 
     @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() );
+        assertEquals( MyTestClass.class.getTypeName(), entry.getName() );
         assertNotNull( entry.getStackTraceWriter() );
+        assertNotNull( entry.getStackTraceWriter().getThrowable() );
+        assertThat( entry.getStackTraceWriter().getThrowable().getTarget() )
+                .isInstanceOf( AssertionError.class );
     }
 
     @Test
@@ -342,7 +345,7 @@ public class RunListenerAdapterTest
 
         adapter.executionFinished( TestIdentifier.from( classDescriptor ), successful() );
 
-        verify( listener ).testSetCompleted( new SimpleReportEntry( JUnitPlatformProvider.class.getName(),
+        verify( listener ).testSetCompleted( new SimpleReportEntry( MyTestClass.class.getName(),
                 MyTestClass.class.getName() ) );
 
         verify( listener, never() ).testSucceeded( any() );
@@ -375,7 +378,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 +391,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 +404,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 +414,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 +439,7 @@ public class RunListenerAdapterTest
 
         ReportEntry value = entryCaptor.getValue();
 
-        assertEquals( "myNamedTestMethod", value.getName() );
+        assertEquals( "some display name", value.getName() );
     }
 
     private static TestIdentifier newMethodIdentifier()
@@ -445,6 +462,12 @@ 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 );
@@ -516,6 +539,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/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..fad855e 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,10 @@ 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() );
+                      succeededTests.get( 0 ).getName() );
     }
 
     public static final class AlwaysSucceeds
@@ -81,7 +81,7 @@ public class JUnitTestSetTest
         @Override
         public void testSucceeded( ReportEntry report )
         {
-            this.succeededTests.add( report );
+            succeededTests.add( report );
         }
 
         @Override
@@ -118,7 +118,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/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-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() );