You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by ti...@apache.org on 2018/01/04 00:00:06 UTC

maven-surefire git commit: [SUREFIRE-1372] Rerunning failing tests fails in combination with Description#createSuiteDescription

Repository: maven-surefire
Updated Branches:
  refs/heads/master 869d6f29f -> 0a81c4897


[SUREFIRE-1372] Rerunning failing tests fails in combination with
Description#createSuiteDescription

 Filtering tests by the tuple of (Class, Method) does not work when a test
 suite is used as a suite may not have (Class, Method) . Filtering by the
 description of the failed test should however work.

 Related Issues:
 - https://github.com/cucumber/cucumber-jvm/issues/1134
 - https://github.com/temyers/cucumber-jvm-parallel-plugin/issues/31

SUREFIRE-1372 Filter junit4 tests to be rerun by description


Project: http://git-wip-us.apache.org/repos/asf/maven-surefire/repo
Commit: http://git-wip-us.apache.org/repos/asf/maven-surefire/commit/0a81c489
Tree: http://git-wip-us.apache.org/repos/asf/maven-surefire/tree/0a81c489
Diff: http://git-wip-us.apache.org/repos/asf/maven-surefire/diff/0a81c489

Branch: refs/heads/master
Commit: 0a81c48971e3ee4b79b0858be7b8f4b13ece7287
Parents: 869d6f2
Author: mpkorstanje <ri...@gmail.com>
Authored: Wed May 10 23:59:31 2017 +0200
Committer: Tibor17 <ti...@apache.org>
Committed: Thu Jan 4 00:50:29 2018 +0100

----------------------------------------------------------------------
 .../src/site/apt/examples/cucumber.apt.vm       | 115 +++++++++++++++++++
 .../apt/examples/rerun-failing-tests.apt.vm     |   5 +
 maven-surefire-plugin/src/site/site.xml         |   1 +
 .../JUnit47RerunFailingTestWithCucumberIT.java  |  81 +++++++++++++
 .../pom.xml                                     |  77 +++++++++++++
 .../org/sample/cucumber/FlakeCucumberTest.java  |  29 +++++
 .../test/java/org/sample/cucumber/StepDefs.java |  56 +++++++++
 .../org/sample/cucumber/Sample.feature          |  10 ++
 .../common/junit4/JUnit4ProviderUtil.java       |  67 ++---------
 .../common/junit4/MatchDescriptions.java        | 104 +++++++++++++++++
 .../common/junit4/JUnit4ProviderUtilTest.java   |  30 ++---
 .../common/junit48/FailingMethodFilter.java     |  85 --------------
 .../surefire/common/junit48/FilterFactory.java  |   7 +-
 .../maven/surefire/junit4/JUnit4Provider.java   |  38 ++----
 .../surefire/junitcore/JUnitCoreProvider.java   |  12 +-
 15 files changed, 518 insertions(+), 199 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/0a81c489/maven-surefire-plugin/src/site/apt/examples/cucumber.apt.vm
----------------------------------------------------------------------
diff --git a/maven-surefire-plugin/src/site/apt/examples/cucumber.apt.vm b/maven-surefire-plugin/src/site/apt/examples/cucumber.apt.vm
new file mode 100644
index 0000000..e0436cc
--- /dev/null
+++ b/maven-surefire-plugin/src/site/apt/examples/cucumber.apt.vm
@@ -0,0 +1,115 @@
+ ------
+ Using Cucumber
+ ------
+ M.P. Korstanje <ri...@gmail.com>
+ ------
+ 2010-10-10
+ ------
+ 
+ ~~ 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.
+
+ ~~ NOTE: For help with the syntax of this file, see:
+ ~~ http://maven.apache.org/doxia/references/apt-format.html 
+
+Using Cucumber with JUnit
+
+* Configuring Cucumber JUnit
+
+  To get started with Cucumber, you need to add the required version of Cucumber JUnit to your project:
+
++---+
+ <dependencies>
+   [...]
+     <dependency>
+         <groupId>io.cucumber</groupId>
+         <artifactId>cucumber-junit</artifactId>
+         <version>${cucumber.version}</version>
+         <scope>test</scope>
+     </dependency>
+   [...]
+ </dependencies>
++---+
+
+ Then create an empty class that uses the Cucumber JUnit runner.
+
+#{if}(${project.artifactId}=="maven-surefire-plugin")
+
++---+
+package org.sample.cucumber;
+
+import org.junit.runner.RunWith;
+
+import cucumber.api.CucumberOptions;
+import cucumber.api.junit.Cucumber;
+
+@RunWith( Cucumber.class )
+public class RunCucumberTest
+{
+  [...]
+}
++---+
+
+#{else}
+
++---+
+package org.sample.cucumber;
+
+import org.junit.runner.RunWith;
+
+import cucumber.api.CucumberOptions;
+import cucumber.api.junit.Cucumber;
+
+@RunWith( Cucumber.class )
+public class RunCucumberIT
+{
+  [...]
+}
++---+
+
+#{end}
+
+  This will execute all scenarios in the package of the runner. By default a glue code is assumed to be in the same
+  package. The <<<...@CucumberOptions>>> annotation can be used to provide additional configuration of Cucumber.
+
+#{if}(${project.artifactId}=="maven-surefire-plugin")
+  Note that in this example the BDD scenarios are executed by the ${thisPlugin} Plugin in the <<<test>>> phase of the
+  build lifecycle.
+
++---+
+mvn test
++---+
+
+#{else}
+  Note that in this example the BDD scenarios are executed by the ${thisPlugin} Plugin in the <<<integration-test>>>
+  phase of the build lifecycle. The ${thisPlugin} Plugin can be invoked by calling the <<<verify>>> phase.
+
++---+
+mvn verify
++---+
+#{end}
+
+* Using JUnit Rules
+
+  The Cucumber supports JUnit annotations <<<...@ClassRule>>>, <<<...@BeforeClass>>> and <<<...@AfterClass>>>. These are
+  invoked around the suite of features. Using these is not recommended as it limits the portability between different
+  runners. Instead it is recommended to use Cucumbers `Before` and `After` hooks to setup scaffolding.
+
+* Using other JUnit features
+
+  The Cucumber runner acts like a suite of a JUnit tests. As such other JUnit features such as Categories, Custom JUnit
+  Listeners and Reporters and re-running failed tests can all be expected to work.

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/0a81c489/maven-surefire-plugin/src/site/apt/examples/rerun-failing-tests.apt.vm
----------------------------------------------------------------------
diff --git a/maven-surefire-plugin/src/site/apt/examples/rerun-failing-tests.apt.vm b/maven-surefire-plugin/src/site/apt/examples/rerun-failing-tests.apt.vm
index 8a6a8bd..c34e2a6 100644
--- a/maven-surefire-plugin/src/site/apt/examples/rerun-failing-tests.apt.vm
+++ b/maven-surefire-plugin/src/site/apt/examples/rerun-failing-tests.apt.vm
@@ -140,6 +140,11 @@ mvn -D${thisPlugin.toLowerCase()}.rerunFailingTestsCount=2 test
   The provider <<<surefire-junit4>>> executes individual test class and consequently re-runs failed tests.
   The provider <<<surefire-junit47>>> executes all test classes and re-runs failed tests afterwards.
 
+* Re-run execution in Cucumber JVM
+
+  Since of 2.21.0 the provider <<<surefire-junit47>>> can rerun scenarios created by <<cucumber-jvm>>
+  2.0.0 and higher.
+
 * Re-run and skip execution
 
   Since of 2.19.1 you can use parameters <<<skipAfterFailureCount>>> and <<<rerunFailingTestsCount>>> together.

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/0a81c489/maven-surefire-plugin/src/site/site.xml
----------------------------------------------------------------------
diff --git a/maven-surefire-plugin/src/site/site.xml b/maven-surefire-plugin/src/site/site.xml
index 2d2e95a..f5497e2 100644
--- a/maven-surefire-plugin/src/site/site.xml
+++ b/maven-surefire-plugin/src/site/site.xml
@@ -41,6 +41,7 @@
       <item name="Using TestNG" href="examples/testng.html"/>
       <item name="Using JUnit" href="examples/junit.html"/>
       <item name="Using POJO Tests" href="examples/pojo-test.html"/>
+      <item name="Using Cucumber" href="examples/cucumber.html"/>
       <item name="Skipping Tests" href="examples/skipping-tests.html"/>
       <item name="Skip After Failure" href="examples/skip-after-failure.html"/>
       <item name="Inclusions and Exclusions of Tests" href="examples/inclusion-exclusion.html"/>

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/0a81c489/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/JUnit47RerunFailingTestWithCucumberIT.java
----------------------------------------------------------------------
diff --git a/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/JUnit47RerunFailingTestWithCucumberIT.java b/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/JUnit47RerunFailingTestWithCucumberIT.java
new file mode 100644
index 0000000..7383783
--- /dev/null
+++ b/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/JUnit47RerunFailingTestWithCucumberIT.java
@@ -0,0 +1,81 @@
+package org.apache.maven.surefire.its;
+
+/*
+ * 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 static org.apache.commons.lang3.JavaVersion.JAVA_1_7;
+import static org.apache.maven.surefire.its.fixture.HelperAssertions.assumeJavaVersion;
+
+import org.apache.maven.surefire.its.fixture.SurefireJUnit4IntegrationTestCase;
+import org.apache.maven.surefire.its.fixture.SurefireLauncher;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Tests using the JUnit 47 provider to rerun failing tests with the cucumber runner. The main
+ * problem that the junit4 provider has with the cucumber runner is that the junit Description
+ * instance created by the runner has a null test class attribute. This requires that tests are
+ * rerun based on their description.
+ *
+ * @author mpkorstanje
+ */
+public class JUnit47RerunFailingTestWithCucumberIT
+    extends SurefireJUnit4IntegrationTestCase {
+
+    @Before
+    public void assumeJdk17() {
+        assumeJavaVersion(JAVA_1_7);
+    }
+
+
+    private SurefireLauncher unpack() {
+        return unpack("junit47-rerun-failing-tests-with-cucumber")
+            .setJUnitVersion("4.12");
+    }
+
+    @Test
+    public void testRerunFailingErrorTestsFalse() {
+        unpack()
+            .maven()
+            .addGoal("-Dsurefire.rerunFailingTestsCount=" + 0)
+            .withFailure()
+            .executeTest()
+            .assertTestSuiteResults(1, 0, 1, 0, 0);
+    }
+
+    @Test
+    public void testRerunFailingErrorTestsWithOneRetry() {
+        unpack()
+            .maven()
+            .addGoal("-Dsurefire.rerunFailingTestsCount=" + 1)
+            .withFailure()
+            .executeTest()
+            .assertTestSuiteResults(1, 0, 1, 0, 0);
+    }
+
+    @Test
+    public void testRerunFailingErrorTestsTwoRetry() {
+        unpack()
+            .maven()
+            .addGoal("-Dsurefire.rerunFailingTestsCount=" + 2)
+            .executeTest()
+            .assertTestSuiteResults(1, 0, 0, 0, 2);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/0a81c489/surefire-integration-tests/src/test/resources/junit47-rerun-failing-tests-with-cucumber/pom.xml
----------------------------------------------------------------------
diff --git a/surefire-integration-tests/src/test/resources/junit47-rerun-failing-tests-with-cucumber/pom.xml b/surefire-integration-tests/src/test/resources/junit47-rerun-failing-tests-with-cucumber/pom.xml
new file mode 100644
index 0000000..24ee294
--- /dev/null
+++ b/surefire-integration-tests/src/test/resources/junit47-rerun-failing-tests-with-cucumber/pom.xml
@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ 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.
+  -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.maven.surefire</groupId>
+        <artifactId>it-parent</artifactId>
+        <version>1.0</version>
+    </parent>
+
+    <artifactId>junit47-rerun-failing-tests-with-cucumber</artifactId>
+    <name>Test for rerun failing cucumber tests in JUnit 47</name>
+
+    <properties>
+        <cucumber.version>2.0.0</cucumber.version>
+    </properties>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-surefire-plugin</artifactId>
+                <version>${surefire.version}</version>
+                <dependencies>
+                    <dependency>
+                        <groupId>org.apache.maven.surefire</groupId>
+                        <artifactId>surefire-junit47</artifactId>
+                        <version>${surefire.version}</version>
+                    </dependency>
+                </dependencies>
+            </plugin>
+        </plugins>
+    </build>
+
+    <dependencies>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <version>${junit.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>io.cucumber</groupId>
+            <artifactId>cucumber-java</artifactId>
+            <version>${cucumber.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>io.cucumber</groupId>
+            <artifactId>cucumber-junit</artifactId>
+            <version>${cucumber.version}</version>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+</project>

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/0a81c489/surefire-integration-tests/src/test/resources/junit47-rerun-failing-tests-with-cucumber/src/test/java/org/sample/cucumber/FlakeCucumberTest.java
----------------------------------------------------------------------
diff --git a/surefire-integration-tests/src/test/resources/junit47-rerun-failing-tests-with-cucumber/src/test/java/org/sample/cucumber/FlakeCucumberTest.java b/surefire-integration-tests/src/test/resources/junit47-rerun-failing-tests-with-cucumber/src/test/java/org/sample/cucumber/FlakeCucumberTest.java
new file mode 100644
index 0000000..ecda87b
--- /dev/null
+++ b/surefire-integration-tests/src/test/resources/junit47-rerun-failing-tests-with-cucumber/src/test/java/org/sample/cucumber/FlakeCucumberTest.java
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ */
+
+package org.sample.cucumber;
+
+import cucumber.api.junit.Cucumber;
+import org.junit.runner.RunWith;
+
+@RunWith( Cucumber.class )
+public class FlakeCucumberTest
+{
+
+}

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/0a81c489/surefire-integration-tests/src/test/resources/junit47-rerun-failing-tests-with-cucumber/src/test/java/org/sample/cucumber/StepDefs.java
----------------------------------------------------------------------
diff --git a/surefire-integration-tests/src/test/resources/junit47-rerun-failing-tests-with-cucumber/src/test/java/org/sample/cucumber/StepDefs.java b/surefire-integration-tests/src/test/resources/junit47-rerun-failing-tests-with-cucumber/src/test/java/org/sample/cucumber/StepDefs.java
new file mode 100644
index 0000000..d253222
--- /dev/null
+++ b/surefire-integration-tests/src/test/resources/junit47-rerun-failing-tests-with-cucumber/src/test/java/org/sample/cucumber/StepDefs.java
@@ -0,0 +1,56 @@
+/*
+ * 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.
+ */
+
+package org.sample.cucumber;
+
+import cucumber.api.java.en.Given;
+import cucumber.api.java.en.Then;
+import cucumber.api.java.en.When;
+
+import static org.junit.Assert.fail;
+
+public class StepDefs
+{
+    private static int testFailures = 0;
+
+    @Given( "^I have some code$" )
+    public void I_have_some_code()
+        throws Throwable
+    {
+        // do nothing
+    }
+
+    @When( "^I run test$" )
+    public void I_run_test()
+        throws Throwable
+    {
+        // do nothing
+    }
+
+    @Then( "^I get a flake$" )
+    public void I_get_a_flake()
+        throws Throwable
+    {
+        // This test will error out with only one retry, but will pass with two
+        if( testFailures < 2 ) {
+            testFailures++;
+            fail( "failing the test on purpose." );
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/0a81c489/surefire-integration-tests/src/test/resources/junit47-rerun-failing-tests-with-cucumber/src/test/resources/org/sample/cucumber/Sample.feature
----------------------------------------------------------------------
diff --git a/surefire-integration-tests/src/test/resources/junit47-rerun-failing-tests-with-cucumber/src/test/resources/org/sample/cucumber/Sample.feature b/surefire-integration-tests/src/test/resources/junit47-rerun-failing-tests-with-cucumber/src/test/resources/org/sample/cucumber/Sample.feature
new file mode 100644
index 0000000..d5b5dac
--- /dev/null
+++ b/surefire-integration-tests/src/test/resources/junit47-rerun-failing-tests-with-cucumber/src/test/resources/org/sample/cucumber/Sample.feature
@@ -0,0 +1,10 @@
+Feature: Sample
+
+	In order to use Maven
+	As a user
+	I want to do tests.
+	
+	Scenario: Do a flake test
+		Given I have some code
+		When I run test
+		Then I get a flake

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/0a81c489/surefire-providers/common-junit4/src/main/java/org/apache/maven/surefire/common/junit4/JUnit4ProviderUtil.java
----------------------------------------------------------------------
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 075d9d9..6b94a64 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
@@ -19,19 +19,14 @@ package org.apache.maven.surefire.common.junit4;
  * under the License.
  */
 
-import java.util.Collection;
-import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
-import java.util.Map;
 import java.util.Set;
 
-import org.apache.maven.surefire.testset.TestSetFailedException;
-
 import org.junit.runner.Description;
+import org.junit.runner.manipulation.Filter;
 import org.junit.runner.notification.Failure;
 
-import static org.apache.maven.surefire.common.junit4.JUnit4Reflector.createRequest;
 import static org.apache.maven.surefire.util.internal.StringUtils.isBlank;
 import static org.junit.runner.Description.TEST_MECHANISM;
 
@@ -44,74 +39,30 @@ import static org.junit.runner.Description.TEST_MECHANISM;
  */
 public final class JUnit4ProviderUtil
 {
-
     private JUnit4ProviderUtil()
     {
         throw new IllegalStateException( "Cannot instantiate." );
     }
 
     /**
-     * Organize all the failures in previous run into a map between test classes and corresponding failing test methods
-     *
-     * @param allFailures all the failures in previous run
-     * @param testClassLoader ClassLoader used for test classes
-     * @return a map between failing test classes and their corresponding failing test methods
-     */
-    public static Map<Class<?>, Set<String>> generateFailingTests( List<Failure> allFailures,
-                                                                   ClassLoader testClassLoader )
-        throws TestSetFailedException
-    {
-        Map<Class<?>, Set<String>> testClassMethods = new HashMap<Class<?>, Set<String>>();
-        Set<ClassMethod> failingTests = generateFailingTests( allFailures );
-        for ( ClassMethod classMethod: failingTests )
-        {
-            try
-            {
-                Class testClassObj = Class.forName( classMethod.getClazz(), false, testClassLoader );
-                Set<String> failingMethods = testClassMethods.get( testClassObj );
-                if ( failingMethods == null )
-                {
-                    failingMethods = new HashSet<String>();
-                    testClassMethods.put( testClassObj, failingMethods );
-                }
-                failingMethods.add( classMethod.getMethod() );
-            }
-            catch ( ClassNotFoundException e )
-            {
-                throw new TestSetFailedException( "Unable to create test class '" + classMethod.getClazz() + "'", e );
-            }
-        }
-        return testClassMethods;
-    }
-
-    /**
-     * Get all test methods from a list of Failures
+     * Get all descriptions from a list of Failures
      *
      * @param allFailures the list of failures for a given test class
-     * @return the list of test methods
+     * @return the list of descriptions
      */
-    public static Set<ClassMethod> generateFailingTests( List<Failure> allFailures )
+    public static Set<Description> generateFailingTestDescriptions( List<Failure> allFailures )
     {
-        Set<ClassMethod> failingMethods = new HashSet<ClassMethod>();
+        Set<Description> failingTestDescriptions = new HashSet<Description>();
 
         for ( Failure failure : allFailures )
         {
             Description description = failure.getDescription();
             if ( description.isTest() && !isFailureInsideJUnitItself( description ) )
             {
-                ClassMethod classMethod = cutTestClassAndMethod( description );
-                if ( classMethod.isValid() )
-                {
-                    failingMethods.add( classMethod );
-                }
+                failingTestDescriptions.add( description );
             }
         }
-        return failingMethods;
-    }
-
-    public static Description createSuiteDescription( Collection<Class<?>> classes )
-    {
-        return createRequest( classes.toArray( new Class[classes.size()] ) ).getRunner().getDescription();
+        return failingTestDescriptions;
     }
 
     public static boolean isFailureInsideJUnitItself( Description failure )
@@ -153,4 +104,8 @@ public final class JUnit4ProviderUtil
         return isBlank( s ) ? null : s;
     }
 
+    public static Filter createMatchAnyDescriptionFilter( Iterable<Description> descriptions )
+    {
+        return new MatchDescriptions( descriptions );
+    }
 }

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/0a81c489/surefire-providers/common-junit4/src/main/java/org/apache/maven/surefire/common/junit4/MatchDescriptions.java
----------------------------------------------------------------------
diff --git a/surefire-providers/common-junit4/src/main/java/org/apache/maven/surefire/common/junit4/MatchDescriptions.java b/surefire-providers/common-junit4/src/main/java/org/apache/maven/surefire/common/junit4/MatchDescriptions.java
new file mode 100644
index 0000000..3275f7f
--- /dev/null
+++ b/surefire-providers/common-junit4/src/main/java/org/apache/maven/surefire/common/junit4/MatchDescriptions.java
@@ -0,0 +1,104 @@
+package org.apache.maven.surefire.common.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.junit.runner.Description;
+import org.junit.runner.manipulation.Filter;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Only run test methods in the given failure set.
+ *
+ * @author mpkorstanje
+ */
+public final class MatchDescriptions
+    extends Filter
+{
+    private final List<Filter> filters = new ArrayList<Filter>();
+
+    public MatchDescriptions( Iterable<Description> descriptions )
+    {
+        for ( Description description : descriptions )
+        {
+            filters.add( matchDescription( description ) );
+        }
+    }
+
+    @Override
+    public boolean shouldRun( Description description )
+    {
+        for ( Filter filter : filters )
+        {
+            if ( filter.shouldRun( description ) )
+            {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public String describe()
+    {
+        StringBuilder description = new StringBuilder( "Matching description " );
+        for ( int i = 0; i < filters.size(); i++ )
+        {
+            description.append( filters.get( i ).describe() );
+            if ( i != filters.size() - 1 )
+            {
+                description.append( " OR " );
+            }
+        }
+        return description.toString();
+    }
+
+    private static Filter matchDescription( final Description desiredDescription )
+    {
+        return new Filter()
+        {
+            @Override
+            public boolean shouldRun( Description description )
+            {
+                if ( description.isTest() )
+                {
+                    return desiredDescription.equals( description );
+                }
+
+                for ( Description each : description.getChildren() )
+                {
+                    if ( shouldRun( each ) )
+                    {
+                        return true;
+                    }
+                }
+
+                return false;
+            }
+
+            @Override
+            public String describe()
+            {
+                return String.format( "Method %s", desiredDescription.getDisplayName() );
+            }
+        };
+    }
+}

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/0a81c489/surefire-providers/common-junit4/src/test/java/org/apache/maven/surefire/common/junit4/JUnit4ProviderUtilTest.java
----------------------------------------------------------------------
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 b05a562..7a2e6da 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,14 +20,11 @@ package org.apache.maven.surefire.common.junit4;
  */
 
 import junit.framework.TestCase;
-import org.apache.maven.surefire.testset.TestSetFailedException;
 import org.junit.runner.Description;
 import org.junit.runner.notification.Failure;
 
 import java.util.ArrayList;
-import java.util.HashSet;
 import java.util.List;
-import java.util.Map;
 import java.util.Set;
 
 import static org.apache.maven.surefire.common.junit4.JUnit4ProviderUtil.*;
@@ -38,9 +35,9 @@ import static org.apache.maven.surefire.common.junit4.JUnit4ProviderUtil.*;
 public class JUnit4ProviderUtilTest
     extends TestCase
 {
-    public void testGenerateFailingTests() throws TestSetFailedException
+    public void testGenerateFailingTestDescriptions()
     {
-        List<Failure> failures = new ArrayList<Failure>(  );
+        List<Failure> failures = new ArrayList<Failure>();
 
         Description test1Description = Description.createTestDescription( T1.class, "testOne" );
         Description test2Description = Description.createTestDescription( T1.class, "testTwo" );
@@ -54,21 +51,14 @@ public class JUnit4ProviderUtilTest
         failures.add( new Failure( test4Description, new AssertionError() ) );
         failures.add( new Failure( test5Description, new RuntimeException() ) );
 
-        Map<Class<?>, Set<String>> result =  generateFailingTests( failures, getClass().getClassLoader() );
+        Set<Description> result = generateFailingTestDescriptions( failures );
 
-        assertEquals( 2, result.size() );
-        Set<String> resultForT1 = result.get( T1.class );
-        Set<String> resultForT2 = result.get( T2.class );
+        assertEquals( 4, result.size() );
 
-        Set<String> expectedResultForT1 = new HashSet<String>();
-        expectedResultForT1.add( "testOne" );
-        expectedResultForT1.add( "testTwo" );
-        Set<String> expectedResultForT2 = new HashSet<String>();
-        expectedResultForT2.add( "testThree" );
-        expectedResultForT2.add( "testFour" );
-
-        assertEquals( expectedResultForT1, resultForT1 );
-        assertEquals( expectedResultForT2, resultForT2 );
+        assertTrue( result.contains( test1Description) );
+        assertTrue( result.contains( test2Description) );
+        assertTrue( result.contains( test3Description) );
+        assertTrue( result.contains( test4Description) );
     }
 
     public void testIllegalTestDescription$NegativeTest()
@@ -97,12 +87,12 @@ public class JUnit4ProviderUtilTest
         assertEquals( T1.class.getName(), classMethod.getClazz() );
     }
 
-    class T1
+    private static class T1
     {
 
     }
 
-    class T2
+    private static class T2
     {
 
     }

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/0a81c489/surefire-providers/common-junit48/src/main/java/org/apache/maven/surefire/common/junit48/FailingMethodFilter.java
----------------------------------------------------------------------
diff --git a/surefire-providers/common-junit48/src/main/java/org/apache/maven/surefire/common/junit48/FailingMethodFilter.java b/surefire-providers/common-junit48/src/main/java/org/apache/maven/surefire/common/junit48/FailingMethodFilter.java
deleted file mode 100644
index e69e7d0..0000000
--- a/surefire-providers/common-junit48/src/main/java/org/apache/maven/surefire/common/junit48/FailingMethodFilter.java
+++ /dev/null
@@ -1,85 +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.shared.utils.io.SelectorUtils;
-import org.junit.runner.Description;
-import org.junit.runner.manipulation.Filter;
-
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Only run test methods in the given input map, indexed by test class
- */
-final class FailingMethodFilter
-    extends Filter
-{
-    // Map from Class -> List of method names. Are the method names hashed to include the signature?
-    private final Map<Class<?>, Set<String>> failingClassMethodPatterns;
-
-    public FailingMethodFilter( Map<Class<?>, Set<String>> failingClassMethodPatterns )
-    {
-        this.failingClassMethodPatterns = failingClassMethodPatterns;
-    }
-
-    @Override
-    public boolean shouldRun( Description description )
-    {
-        return isDescriptionMatch( description );
-    }
-
-    private boolean isDescriptionMatch( Description description )
-    {
-        if ( description.getTestClass() == null || description.getMethodName() == null )
-        {
-            for ( Description childrenDescription : description.getChildren() )
-            {
-                if ( isDescriptionMatch( childrenDescription ) )
-                {
-                    return true;
-                }
-            }
-            return false;
-        }
-
-        Set<String> testMethodPatterns = failingClassMethodPatterns.get( description.getTestClass() );
-        String testMethod = description.getMethodName();
-        return testMethodPatterns != null && matchMethod( testMethodPatterns, testMethod );
-    }
-
-    private static boolean matchMethod( Set<String> patterns, String methodName )
-    {
-        for ( String pattern : patterns )
-        {
-            if ( SelectorUtils.match( pattern, methodName ) )
-            {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    @Override
-    public String describe()
-    {
-        return "By failing class method";
-    }
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/0a81c489/surefire-providers/common-junit48/src/main/java/org/apache/maven/surefire/common/junit48/FilterFactory.java
----------------------------------------------------------------------
diff --git a/surefire-providers/common-junit48/src/main/java/org/apache/maven/surefire/common/junit48/FilterFactory.java b/surefire-providers/common-junit48/src/main/java/org/apache/maven/surefire/common/junit48/FilterFactory.java
index 228ca6d..6ebff47 100644
--- a/surefire-providers/common-junit48/src/main/java/org/apache/maven/surefire/common/junit48/FilterFactory.java
+++ b/surefire-providers/common-junit48/src/main/java/org/apache/maven/surefire/common/junit48/FilterFactory.java
@@ -19,14 +19,15 @@ package org.apache.maven.surefire.common.junit48;
  * under the License.
  */
 
+import org.apache.maven.surefire.common.junit4.JUnit4ProviderUtil;
 import org.apache.maven.surefire.group.match.GroupMatcher;
 import org.apache.maven.surefire.group.parse.GroupMatcherParser;
 import org.apache.maven.surefire.group.parse.ParseException;
 import org.apache.maven.surefire.testset.TestListResolver;
+import org.junit.runner.Description;
 import org.junit.runner.manipulation.Filter;
 
 import java.util.Map;
-import java.util.Set;
 
 import static org.apache.maven.surefire.booter.ProviderParameterNames.TESTNG_EXCLUDEDGROUPS_PROP;
 import static org.apache.maven.surefire.booter.ProviderParameterNames.TESTNG_GROUPS_PROP;
@@ -118,9 +119,9 @@ public class FilterFactory
         return new MethodFilter( resolver );
     }
 
-    public Filter createFailingMethodFilter( Map<Class<?>, Set<String>> failingClassMethodMap )
+    public Filter createMatchAnyDescriptionFilter( Iterable<Description> descriptions )
     {
-        return new FailingMethodFilter( failingClassMethodMap );
+        return JUnit4ProviderUtil.createMatchAnyDescriptionFilter( descriptions );
     }
 
     public Filter and( Filter filter1, Filter filter2 )

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/0a81c489/surefire-providers/surefire-junit4/src/main/java/org/apache/maven/surefire/junit4/JUnit4Provider.java
----------------------------------------------------------------------
diff --git a/surefire-providers/surefire-junit4/src/main/java/org/apache/maven/surefire/junit4/JUnit4Provider.java b/surefire-providers/surefire-junit4/src/main/java/org/apache/maven/surefire/junit4/JUnit4Provider.java
index ad29224..c31a019 100644
--- a/surefire-providers/surefire-junit4/src/main/java/org/apache/maven/surefire/junit4/JUnit4Provider.java
+++ b/surefire-providers/surefire-junit4/src/main/java/org/apache/maven/surefire/junit4/JUnit4Provider.java
@@ -22,7 +22,6 @@ package org.apache.maven.surefire.junit4;
 import org.apache.maven.surefire.booter.Command;
 import org.apache.maven.surefire.booter.CommandListener;
 import org.apache.maven.surefire.booter.CommandReader;
-import org.apache.maven.surefire.common.junit4.ClassMethod;
 import org.apache.maven.surefire.common.junit4.JUnit4RunListener;
 import org.apache.maven.surefire.common.junit4.JUnit4TestChecker;
 import org.apache.maven.surefire.common.junit4.JUnitTestFailureListener;
@@ -46,7 +45,6 @@ import org.junit.runner.Request;
 import org.junit.runner.Result;
 import org.junit.runner.Runner;
 import org.junit.runner.manipulation.Filter;
-import org.junit.runner.notification.RunNotifier;
 import org.junit.runner.notification.StoppedByUserException;
 
 import java.util.Collection;
@@ -55,7 +53,9 @@ import java.util.Set;
 import static java.lang.reflect.Modifier.isAbstract;
 import static java.lang.reflect.Modifier.isInterface;
 import static org.apache.maven.surefire.booter.CommandReader.getReader;
-import static org.apache.maven.surefire.common.junit4.JUnit4ProviderUtil.generateFailingTests;
+import static org.apache.maven.surefire.common.junit4.JUnit4ProviderUtil.createMatchAnyDescriptionFilter;
+import static org.apache.maven.surefire.common.junit4.JUnit4ProviderUtil.generateFailingTestDescriptions;
+import static org.apache.maven.surefire.common.junit4.JUnit4ProviderUtil.isFailureInsideJUnitItself;
 import static org.apache.maven.surefire.common.junit4.JUnit4Reflector.createDescription;
 import static org.apache.maven.surefire.common.junit4.JUnit4Reflector.createIgnored;
 import static org.apache.maven.surefire.common.junit4.JUnit4RunListener.rethrowAnyTestMechanismFailures;
@@ -67,7 +67,6 @@ import static org.apache.maven.surefire.testset.TestListResolver.optionallyWildc
 import static org.apache.maven.surefire.util.TestsToRun.fromClass;
 import static org.apache.maven.surefire.util.internal.ObjectUtils.systemProps;
 import static org.junit.runner.Request.aClass;
-import static org.junit.runner.Request.method;
 
 /**
  * @author Kristian Rosenvold
@@ -261,7 +260,6 @@ public class JUnit4Provider
     }
 
     private void executeWithRerun( Class<?> clazz, Notifier notifier )
-        throws TestSetFailedException
     {
         JUnitTestFailureListener failureListener = new JUnitTestFailureListener();
         notifier.addListener( failureListener );
@@ -286,12 +284,10 @@ public class JUnit4Provider
                 notifier.copyListenersTo( rerunNotifier );
                 for ( int i = 0; i < rerunFailingTestsCount && !failureListener.getAllFailures().isEmpty(); i++ )
                 {
-                    Set<ClassMethod> failedTests = generateFailingTests( failureListener.getAllFailures() );
+                    Set<Description> failures = generateFailingTestDescriptions( failureListener.getAllFailures() );
                     failureListener.reset();
-                    if ( !failedTests.isEmpty() )
-                    {
-                        executeFailedMethod( rerunNotifier, failedTests );
-                    }
+                    Filter failureDescriptionFilter = createMatchAnyDescriptionFilter( failures );
+                    execute( clazz, rerunNotifier, failureDescriptionFilter );
                 }
             }
         }
@@ -371,24 +367,6 @@ public class JUnit4Provider
         }
     }
 
-    private void executeFailedMethod( RunNotifier notifier, Set<ClassMethod> failedMethods )
-        throws TestSetFailedException
-    {
-        for ( ClassMethod failedMethod : failedMethods )
-        {
-            try
-            {
-                Class<?> methodClass = Class.forName( failedMethod.getClazz(), true, testClassLoader );
-                String methodName = failedMethod.getMethod();
-                method( methodClass, methodName ).getRunner().run( notifier );
-            }
-            catch ( ClassNotFoundException e )
-            {
-                throw new TestSetFailedException( "Unable to create test class '" + failedMethod.getClazz() + "'", e );
-            }
-        }
-    }
-
     /**
      * JUnit error: test count includes one test-class as a suite which has filtered out all children.
      * Then the child test has a description "initializationError0(org.junit.runner.manipulation.Filter)"
@@ -422,6 +400,10 @@ public class JUnit4Provider
 
     private static boolean hasFilteredOutAllChildren( Description description )
     {
+        if ( isFailureInsideJUnitItself( description ) )
+        {
+            return true;
+        }
         String name = description.getDisplayName();
         // JUnit 4.0: initializationError0; JUnit 4.12: initializationError.
         if ( name == null )

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/0a81c489/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/JUnitCoreProvider.java
----------------------------------------------------------------------
diff --git a/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/JUnitCoreProvider.java b/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/JUnitCoreProvider.java
index a4c061e..a652515 100644
--- a/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/JUnitCoreProvider.java
+++ b/surefire-providers/surefire-junit47/src/main/java/org/apache/maven/surefire/junitcore/JUnitCoreProvider.java
@@ -39,16 +39,15 @@ import org.apache.maven.surefire.util.RunOrderCalculator;
 import org.apache.maven.surefire.util.ScanResult;
 import org.apache.maven.surefire.util.ScannerFilter;
 import org.apache.maven.surefire.util.TestsToRun;
+import org.junit.runner.Description;
 import org.junit.runner.manipulation.Filter;
-import org.junit.runner.notification.Failure;
 
-import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 
 import static org.apache.maven.surefire.booter.CommandReader.getReader;
-import static org.apache.maven.surefire.common.junit4.JUnit4ProviderUtil.generateFailingTests;
+import static org.apache.maven.surefire.common.junit4.JUnit4ProviderUtil.generateFailingTestDescriptions;
 import static org.apache.maven.surefire.common.junit4.JUnit4RunListenerFactory.createCustomListeners;
 import static org.apache.maven.surefire.common.junit4.Notifier.pureNotifier;
 import static org.apache.maven.surefire.junitcore.ConcurrentRunListener.createInstance;
@@ -167,12 +166,11 @@ public class JUnitCoreProvider
                 JUnitCoreWrapper rerunCore = new JUnitCoreWrapper( rerunNotifier, jUnitCoreParameters, consoleStream );
                 for ( int i = 0; i < rerunFailingTestsCount && !testFailureListener.getAllFailures().isEmpty(); i++ )
                 {
-                    List<Failure> failures = testFailureListener.getAllFailures();
-                    Map<Class<?>, Set<String>> failingTests = generateFailingTests( failures, testClassLoader );
+                    Set<Description> failures = generateFailingTestDescriptions( testFailureListener.getAllFailures() );
                     testFailureListener.reset();
                     FilterFactory filterFactory = new FilterFactory( testClassLoader );
-                    Filter failingMethodsFilter = filterFactory.createFailingMethodFilter( failingTests );
-                    rerunCore.execute( testsToRun, failingMethodsFilter );
+                    Filter failureDescriptionFilter = filterFactory.createMatchAnyDescriptionFilter( failures );
+                    rerunCore.execute( testsToRun, failureDescriptionFilter );
                 }
             }
         }