【问题标题】:Rerunning failed cucumber tests using cucumber-jvm使用 cucumber-jvm 重新运行失败的黄瓜测试
【发布时间】:2014-01-24 13:39:53
【问题描述】:

我有一个 Cucumber-JVM、JUnit、Selenium 设置。我通过在 Eclipse 中使用 JUnit 运行 RunSmokeTests.java 来启动运行。我还设置了一个 Maven 配置文件来从命令行运行测试,将来可能还有 Jenkins。

当测试运行时,其中一些有时可能会失败,主要是由于应用程序花费的时间比预期的要长。然后我将不得不重新运行这些场景。目前我通过手动将@rerun标签附加到失败的标签上运行它们,然后运行RunReruns.java,这类似于RunSmokeTest.java,但带有@rerun标签。

随着自动化测试数量的增加,标记测试并开始运行和清除标记非常耗时。是否有使用 Cucumber-JVM 自动重新运行失败测试的方法?

RunSmokeTests.java

package testGlueClasses;
import cucumber.api.junit.Cucumber;
import org.junit.runner.RunWith;

@RunWith(Cucumber.class)
@Cucumber.Options(features = "src/test/java", strict = true, format = {
        "html:target/CucumberReport", "json:target/JSON/Cucumber.json",
        "FrameworkCore.CustomTestReporter" }, tags = { "@SmokeTest" }, glue = {
        "FrameworkCore", "MyApp.Utils", "MyApp.StepDefinitions" })
public class RunSmokeTests {

} 

Maven sn-p:

    <profile>
        <id>smoke</id>
        <properties>
            <include.tests>
                **/RunSmokeTests.java
            </include.tests>
        </properties>
    </profile>

【问题讨论】:

  • @Bala - 是的,我已经看到了。我相信这些命令适用于 Cucumber Ruby,或者至少我看不到如何使用 Cucumber-JVM 运行这些命令。你以前用 Cucumber-JVM 做过这个吗?

标签: java maven cucumber-jvm cucumber-junit


【解决方案1】:

我想出了另一个解决方案,使用 maven 和 cucumber 重新运行刚刚失败的测试。

1) 使用RunNotifier 记录测试失败

public class RerunningCucumber extends Cucumber {

    private final String className;

    @SuppressWarnings("rawtypes")
    public RerunningCucumber(Class clazz) throws InitializationError, IOException {
        super(clazz);
        className = clazz.getSimpleName();
    }


    @Override
    public void run(RunNotifier notifier) {
        notifier.addListener(new RunListener(){

            public void testFailure(Failure failure) throws Exception {

                Throwable error = failure.getException();
                if (error instanceof AssertionError){
                    //Nothing. This is a normal failure. Continue
                    return;
                }

                //No! A wild exception has appeared!
                //Let's run this test again.
                RerunningCucumber.addFile(className);
            }

        });
        super.run(notifier);
    }


    private static final String filename = "target/rerun.properties";
    private static final Set<String> addedClasses = new HashSet<String>();
    public static synchronized void addFile(String className) throws IOException{
        //First find the file

        if (addedClasses.contains(className)){
            return;
        }

        File file = new File(filename);
        if (!file.exists()){
            //Need to create the file
            PrintWriter writer = new PrintWriter(file, "UTF-8");
            writer.print("retryclasses=**/"+className+".class");
            writer.close();
        }
        else {
            PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(file, true)));
            out.print(",**/"+className+".class");
            out.close();
        }

        addedClasses.add(className);
    }
}

2) 使用自定义类作为黄瓜测试的运行器。

这将运行测试,并且每当出现故障时,将失败的类输出到文件中。诀窍是保持功能简短并创建大量测试类以避免重复测试。

@RunWith(RerunningCucumber.class)
@CucumberOptions(features = {"classpath:features/testFeature.feature}, format = {
        "html:target/cucumber-html-report/testFeature.html",
        "json:target/cucumber-json-report/testFeature.json"},
        tags = {"@testFeature"})

public class RunTestFeature {
}

3) 将 Rerun 配置文件添加到 maven。

这做了三件事:1) 它将失败的类加载到内存中,2) 只清理失败的类属性文件,3) 只重新运行从属性文件加载的失败的测试:

    <profile>
        <id>retry</id>
        <build>
            <plugins>
                <plugin>
                    <groupId>org.codehaus.mojo</groupId>
                    <artifactId>properties-maven-plugin</artifactId>
                    <version>1.0-alpha-2</version>
                    <executions>
                        <!-- Associate the read-project-properties goal with the initialize 
                            phase, to read the properties file. -->
                        <execution>
                            <phase>pre-clean</phase>
                            <goals>
                                <goal>read-project-properties</goal>
                            </goals>
                            <configuration>
                                <files>
                                    <file>target/rerun.properties</file>
                                </files>
                            </configuration>
                        </execution>
                    </executions>
                </plugin>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-clean-plugin</artifactId>
                    <version>2.6.1</version>
                    <configuration>
                        <filesets>
                            <fileset>
                                <directory>target</directory>
                                <includes>
                                    <include>rerun.properties</include>
                                </includes>
                            </fileset>
                        </filesets>
                    </configuration>
                </plugin>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-antrun-plugin</artifactId>
                    <version>1.6</version>
                    <executions>
                        <execution>
                            <phase>compile</phase>
                            <goals>
                                <goal>run</goal>
                            </goals>
                            <configuration>
                                <target>
                                    <echo>Retrying the following classes: "${retryclasses}"</echo>
                                </target>
                            </configuration>
                        </execution>
                    </executions>
                </plugin>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-surefire-plugin</artifactId>
                    <version>2.17</version>
                    <configuration>
                        <includes>
                            <include>${retryclasses}</include>
                        </includes>
                        <testFailureIgnore>true</testFailureIgnore>
                    </configuration>
                    <executions>
                        <execution>
                            <phase>test</phase>
                            <goals>
                                <goal>test</goal>
                            </goals>
                        </execution>
                    </executions>
                </plugin>
            </plugins>
        </build>
    </profile>

4) 用法

第一次试运行:

mvn clean test

下一个测试运行:

mvn clean test -Pretry
mvn clean test -Pretry
mvn clean test -Pretry
...

您可以根据需要重复多次,直到没有错误为止。

【讨论】:

  • 有趣的解决方案,但每个功能需要一个类似乎有点麻烦。你能再解释一下为什么黄瓜的重播功能不适合你吗?
  • 我认为这是两件事:1)当我指定 rerun.txt 文件作为输入特征时,它没有重新运行那些测试用例;只是很困惑。 2) 我无法指定测试运行顺序以保证重新运行程序最后运行。
  • 什么是 ${retryclasses} ?
  • @Jason,io.cucumber.junit.Cucumber 类是最终的。我假设你在人们使用cukes黄瓜类的时候这样做。曾经设法用新的黄瓜类实现这样的目标吗?我似乎无法使用 rerun.txt,因为当测试并行运行时,并非所有失败的场景都会记录到 rerun.txt。所以我很想看看我怎样才能让它发挥作用。谢谢
【解决方案2】:

我手头没有可执行的示例,但您也可以在 jvm 上执行此操作。有一个RerunFormatter 写了一个文本文件,列出了失败场景的文件和行号:

@CucumberOptions(format = {"rerun:target/rerun.txt"})

您应该能够将此文件指定为另一个测试类的输入,方法是在其前面加上 @:

@CucumberOptions(features = {"@target/rerun.txt"})

【讨论】:

  • 我们新建一个测试类,然后添加@CucumberOptions(features = {"@target/rerun.txt"})?你知道在 Maven 中让这个文件最后运行的方法吗?
  • 我正在考虑在一个单独的 Maven 配置文件中指定重新运行测试,当您看到测试失败时可以执行该配置文件。不过,这不会是完全自动化的。我认为 junit 或 maven 不能保证类的执行顺序,但您可以将它们分组到一个测试套件中:junit.sourceforge.net/javadoc/org/junit/runners/Suite.html
【解决方案3】:

您可以将黄瓜选项传递给 mvn,如下所示

 mvn clean verify  -Dcucumber.options="@rerun.txt"

注意这里有一个棘手的部分。如果您在首次运行和重新运行时使用相同的测试运行程序(我相信这就是您想要的),那么测试运行程序将包含类似

@CucumberOptions(plugin = { "rerun:target/rerun.txt"})

如果您使用与以下相同的重新运行文件名使用 maven 重新运行

 mvn clean verify  -Dcucumber.options="@target/rerun.txt"

然后黄瓜会抱怨它找不到重新运行的文件。为什么?因为插件“rerun:target/rerun.txt”会先用这个测试运行器删除文件。

解决方法是先复制/重命名文件,然后像这样启动 mvn 运行

mv target/rerun.txt rerun.txt &&  mvn clean verify  -Dcucumber.options="@rerun.txt"

这实际上就是你想要的。因为假设文件 target/rerun.txt 中有 5 个失败的场景。在一些修复后重新运行,其中 2 个通过了。现在 target/rerun.txt 将只包含其余 3 个失败的场景,这将是您在调试过程中的新起点。

【讨论】:

    【解决方案4】:

    对于 maven 上的 cucumber + java,我找到了这个命令:

    mvn clean test -Dsurefire.rerunFailingTestsCount=2
    

    你必须有一个surefire插件的实际版本,我的是3.0.0-M5。 没有什么特别的你甚至需要。 在这里找到解决方案Surefire rerun failing tests not working

    【讨论】:

      【解决方案5】:

      1) 使用 junit4 (cucumber-junit 引擎) 可以使用 rerun 插件轻松完成 和features 黄瓜选项。为运行失败的场景添加另一个 maven 配置文件,例如 RerunCucumber.class。

      使用主测试运行器运行您的初始构建并通过rerun 插件:

      @RunWith(Cucumber.class)
      @CucumberOptions(tags = "@wip",
              monochrome = true,
              plugin = {"html:target/cucumber", "json:target/wip.json", "rerun:target/rerun_wip.txt"})
      public class RunCucumber {
      }
      

      构建完成后,失败的场景将写入target/rerun_wip.txt

      然后可以通过rerunner执行失败的场景:

      @RunWith(Cucumber.class)
      @CucumberOptions(features = {"@features = {"@target/rerun_wip.txt"}"},
              monochrome = true,
              plugin = {"html:target/rerun/failed_tests", "json:target/rerun/failed_tests.json"})
      public class RerunCucumber {
      }
      

      将从target/rerun_wip.txt 执行测试。

      2) 使用 junit5 (cucumber-junit-platform-engine) 没有这样的方法(没有 features cucumber 选项)。有关使用 junit5 重新运行失败场景的更多信息:https://github.com/cucumber/cucumber-jvm/tree/main/junit-platform-engine,在“重新运行失败的场景”部分

      【讨论】:

        【解决方案6】:

        您可以使用cucumber-jvm-parallel-plugin 贡献的代码作为解决方法,直到它上线为止。点击命令如下图。

        1. git clone -b tagwiseOutlinewiseIssueRerun https://github.com/sugatmankar/cucumber-jvm-parallel-plugin.git
        2. mvn 全新安装。
        3. 现在编辑您的项目 pom 文件并按照here 的说明使用。
        4. 使用这个插件的例子是here

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-05-14
          • 2021-03-20
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-04-07
          相关资源
          最近更新 更多