Java 如何并行执行黄瓜特征文件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/41034116/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 23:06:24  来源:igfitidea点击:

How to execute cucumber feature file parallel

javacucumbertestngcucumber-jvm

提问by ArrchanaMohan

I have below feature files (Separate feature files) in src/test/resources/feature/ and I would like to run them in parallel. Like: One feature file has to execute in chrome and another one has to execute in firefox as mentioned @Tags name.

我在 src/test/resources/feature/ 中有以下功能文件(单独的功能文件),我想并行运行它们。如:一个功能文件必须在 chrome 中执行,另一个必须在 firefox 中执行,如@Tags 名称所述。

Feature: Refund item

@chrome
  Scenario: Jeff returns a faulty microwave
    Given Jeff has bought a microwave for 0
    And he has a receipt
    When he returns the microwave
    Then Jeff should be refunded 0

Feature: Refund Money

@firefox
  Scenario: Jeff returns the money
    Given Jeff has bought a microwave for 0
    And he has a receipt
    When he returns the microwave
    Then Jeff should be refunded 0

Can somebody assist me to achieve this.I'm using cucumber-java 1.2.2 version, and AbstractTestNGCucumberTests using as runner. Also, let me know how can I create a Test Runner dynamically by using feature files and make them run in parallel.

有人可以帮助我实现这一点。我使用的是黄瓜 Java 1.2.2 版本,而 AbstractTestNGCucumberTests 用作跑步者。另外,让我知道如何使用功能文件动态创建测试运行器并使它们并行运行。

采纳答案by Sugat Mankar

Update:4.0.0 version is available at maven central repository with bunch of changes.for more details go here.

更新:4.0.0 版本可在 maven 中央存储库中获得,并进行了大量更改。有关更多详细信息,请访问此处。

Update:2.2.0 version is available at maven central repository.

更新:2.2.0 版本在 maven 中央存储库中可用。

You can use opensource plugin cucumber-jvm-parallel-pluginwhich has many advantages over existing solutions. Available at maven repository

你可以使用开源插件cucumber-jvm-parallel-plugin,它比现有的解决方案有很多优势。可在 Maven存储库中使用

   <dependency>
     <groupId>com.github.temyers</groupId>
     <artifactId>cucumber-jvm-parallel-plugin</artifactId>
     <version>2.1.0</version>
   </dependency>
  1. First you need to add this plugin with required configuration in your project pom file.

    <plugin>
      <groupId>com.github.temyers</groupId>
      <artifactId>cucumber-jvm-parallel-plugin</artifactId>
      <version>2.1.0</version>
      <executions>
         <execution>
         <id>generateRunners</id>
         <phase>generate-test-sources</phase>
         <goals>
           <goal>generateRunners</goal>
         </goals>
         <configuration>
             <!-- Mandatory -->
             <!-- comma separated list of package names to scan for glue code -->
             <glue>foo, bar</glue>
             <outputDirectory>${project.build.directory}/generated-test-sources/cucumber</outputDirectory>
              <!-- The directory, which must be in the root of the runtime classpath, containing your feature files.  -->
               <featuresDirectory>src/test/resources/features/</featuresDirectory>
              <!-- Directory where the cucumber report files shall be written  -->
              <cucumberOutputDir>target/cucumber-parallel</cucumberOutputDir>
              <!-- comma separated list of output formats json,html,rerun.txt -->
              <format>json</format>
              <!-- CucumberOptions.strict property -->
              <strict>true</strict>
              <!-- CucumberOptions.monochrome property -->
              <monochrome>true</monochrome>
              <!-- The tags to run, maps to CucumberOptions.tags property you can pass ANDed tags like "@tag1","@tag2" and ORed tags like "@tag1,@tag2,@tag3" -->
             <tags></tags>
             <!-- If set to true, only feature files containing the required tags shall be generated. -->
             <filterFeaturesByTags>false</filterFeaturesByTags>
             <!-- Generate TestNG runners instead of default JUnit ones. --> 
             <useTestNG>false</useTestNG>
             <!-- The naming scheme to use for the generated test classes.  One of 'simple' or 'feature-title' --> 
            <namingScheme>simple</namingScheme>
            <!-- The class naming pattern to use.  Only required/used if naming scheme is 'pattern'.-->
            <namingPattern>Parallel{c}IT</namingPattern>
            <!-- One of [SCENARIO, FEATURE]. SCENARIO generates one runner per scenario.  FEATURE generates a runner per feature. -->
            <parallelScheme>SCENARIO</parallelScheme>
            <!-- This is optional, required only if you want to specify a custom template for the generated sources (this is a relative path) -->
            <customVmTemplate>src/test/resources/cucumber-custom-runner.vm</customVmTemplate>
            </configuration>
           </execution>
         </executions>
       </plugin>
    
  2. Now add below plugin just below above plugin which will invoke runner classes generated by above plugin

        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-surefire-plugin</artifactId>
            <version>2.19</version>
            <configuration> 
                <forkCount>5</forkCount>
                <reuseForks>true</reuseForks>
                <includes>
                    <include>**/*IT.class</include>
                </includes>
            </configuration>
        </plugin>
    
  3. Above two plugins will do magic for cucumber test running in parallel (provided you machine also have advanced hardware support).

  4. Strictly provided <forkCount>n</forkCount>here 'n' is directly proportional to 1) Advanced Hardware support and 2) you available nodes i.e. registered browser instances to HUB.

  5. One major and most important changes is your WebDriver class must be SHAREDand you should notimplement driver.quit() method, as closing is take care by shutdown hook.

    import cucumber.api.Scenario;
    import cucumber.api.java.After;
    import cucumber.api.java.Before;
    import org.openqa.selenium.OutputType;
    import org.openqa.selenium.WebDriver;
    import org.openqa.selenium.WebDriverException;
    import org.openqa.selenium.firefox.FirefoxDriver;
    import org.openqa.selenium.support.events.EventFiringWebDriver;
    
    public class SharedDriver extends EventFiringWebDriver {
        private static WebDriver REAL_DRIVER = null;
    
    
    
        private static final Thread CLOSE_THREAD = new Thread() {
            @Override
            public void run() {
                REAL_DRIVER.close();
            }
        };
    
        static {
            Runtime.getRuntime().addShutdownHook(CLOSE_THREAD);
        }
    
        public SharedDriver() {
            super(CreateDriver());
        }
    
        public static WebDriver CreateDriver() {
            WebDriver webDriver;
            if (REAL_DRIVER == null)
                webDriver = new FirefoxDriver();
            setWebDriver(webDriver);
            return webDriver;
        }
    
        public static void setWebDriver(WebDriver webDriver) {
            this.REAL_DRIVER = webDriver;
        }
    
        public static WebDriver getWebDriver() {
            return this.REAL_DRIVER;
        }
    
        @Override
        public void close() {
            if (Thread.currentThread() != CLOSE_THREAD) {
                throw new UnsupportedOperationException("You shouldn't close this WebDriver. It's shared and will close when the JVM exits.");
            }
            super.close();
        }
    
        @Before
        public void deleteAllCookies() {
            manage().deleteAllCookies();
        }
    
        @After
        public void embedScreenshot(Scenario scenario) {
            try {
                byte[] screenshot = getScreenshotAs(OutputType.BYTES);
                scenario.embed(screenshot, "image/png");
            } catch (WebDriverException somePlatformsDontSupportScreenshots) {
                System.err.println(somePlatformsDontSupportScreenshots.getMessage());
            }
        }
    }
    
  6. Considering you want to execute more than 50 threads i.e. same no of browser instances are registered to HUB but Hub will die if it doesn't get enough memory therefore to avoid this critical situation you should start hub with -DPOOL_MAX=512 (or larger) as stated in grid2 documentation.

    Really large (>50 node) Hub installations may need to increase the jetty threads by setting -DPOOL_MAX=512 (or larger) on the java command line.

    java -jar selenium-server-standalone-<version>.jar -role hub -DPOOL_MAX=512

  1. 首先,您需要在项目 pom 文件中添加具有所需配置的插件。

    <plugin>
      <groupId>com.github.temyers</groupId>
      <artifactId>cucumber-jvm-parallel-plugin</artifactId>
      <version>2.1.0</version>
      <executions>
         <execution>
         <id>generateRunners</id>
         <phase>generate-test-sources</phase>
         <goals>
           <goal>generateRunners</goal>
         </goals>
         <configuration>
             <!-- Mandatory -->
             <!-- comma separated list of package names to scan for glue code -->
             <glue>foo, bar</glue>
             <outputDirectory>${project.build.directory}/generated-test-sources/cucumber</outputDirectory>
              <!-- The directory, which must be in the root of the runtime classpath, containing your feature files.  -->
               <featuresDirectory>src/test/resources/features/</featuresDirectory>
              <!-- Directory where the cucumber report files shall be written  -->
              <cucumberOutputDir>target/cucumber-parallel</cucumberOutputDir>
              <!-- comma separated list of output formats json,html,rerun.txt -->
              <format>json</format>
              <!-- CucumberOptions.strict property -->
              <strict>true</strict>
              <!-- CucumberOptions.monochrome property -->
              <monochrome>true</monochrome>
              <!-- The tags to run, maps to CucumberOptions.tags property you can pass ANDed tags like "@tag1","@tag2" and ORed tags like "@tag1,@tag2,@tag3" -->
             <tags></tags>
             <!-- If set to true, only feature files containing the required tags shall be generated. -->
             <filterFeaturesByTags>false</filterFeaturesByTags>
             <!-- Generate TestNG runners instead of default JUnit ones. --> 
             <useTestNG>false</useTestNG>
             <!-- The naming scheme to use for the generated test classes.  One of 'simple' or 'feature-title' --> 
            <namingScheme>simple</namingScheme>
            <!-- The class naming pattern to use.  Only required/used if naming scheme is 'pattern'.-->
            <namingPattern>Parallel{c}IT</namingPattern>
            <!-- One of [SCENARIO, FEATURE]. SCENARIO generates one runner per scenario.  FEATURE generates a runner per feature. -->
            <parallelScheme>SCENARIO</parallelScheme>
            <!-- This is optional, required only if you want to specify a custom template for the generated sources (this is a relative path) -->
            <customVmTemplate>src/test/resources/cucumber-custom-runner.vm</customVmTemplate>
            </configuration>
           </execution>
         </executions>
       </plugin>
    
  2. 现在在插件上面添加下面的插件,这将调用上面插件生成的运行器类

        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-surefire-plugin</artifactId>
            <version>2.19</version>
            <configuration> 
                <forkCount>5</forkCount>
                <reuseForks>true</reuseForks>
                <includes>
                    <include>**/*IT.class</include>
                </includes>
            </configuration>
        </plugin>
    
  3. 以上两个插件将为并行运行的黄瓜测试发挥神奇作用(前提是您的机器还具有高级硬件支持)。

  4. <forkCount>n</forkCount>此处严格提供的 “n”与 1) 高级硬件支持和 2) 您可用的节点成正比,即向 HUB 注册浏览器实例。

  5. 一个主要的和最重要的变化是你的webdriver类必须是SHARED,你应该执行driver.quit()方法,如封闭是照管关闭挂钩。

    import cucumber.api.Scenario;
    import cucumber.api.java.After;
    import cucumber.api.java.Before;
    import org.openqa.selenium.OutputType;
    import org.openqa.selenium.WebDriver;
    import org.openqa.selenium.WebDriverException;
    import org.openqa.selenium.firefox.FirefoxDriver;
    import org.openqa.selenium.support.events.EventFiringWebDriver;
    
    public class SharedDriver extends EventFiringWebDriver {
        private static WebDriver REAL_DRIVER = null;
    
    
    
        private static final Thread CLOSE_THREAD = new Thread() {
            @Override
            public void run() {
                REAL_DRIVER.close();
            }
        };
    
        static {
            Runtime.getRuntime().addShutdownHook(CLOSE_THREAD);
        }
    
        public SharedDriver() {
            super(CreateDriver());
        }
    
        public static WebDriver CreateDriver() {
            WebDriver webDriver;
            if (REAL_DRIVER == null)
                webDriver = new FirefoxDriver();
            setWebDriver(webDriver);
            return webDriver;
        }
    
        public static void setWebDriver(WebDriver webDriver) {
            this.REAL_DRIVER = webDriver;
        }
    
        public static WebDriver getWebDriver() {
            return this.REAL_DRIVER;
        }
    
        @Override
        public void close() {
            if (Thread.currentThread() != CLOSE_THREAD) {
                throw new UnsupportedOperationException("You shouldn't close this WebDriver. It's shared and will close when the JVM exits.");
            }
            super.close();
        }
    
        @Before
        public void deleteAllCookies() {
            manage().deleteAllCookies();
        }
    
        @After
        public void embedScreenshot(Scenario scenario) {
            try {
                byte[] screenshot = getScreenshotAs(OutputType.BYTES);
                scenario.embed(screenshot, "image/png");
            } catch (WebDriverException somePlatformsDontSupportScreenshots) {
                System.err.println(somePlatformsDontSupportScreenshots.getMessage());
            }
        }
    }
    
  6. 考虑到您要执行超过 50 个线程,即相同数量的浏览器实例注册到 HUB,但如果没有足够的内存,Hub 就会死掉,因此为避免这种危急情况,您应该使用 -DPOOL_MAX=512(或更大)启动 hub如grid2 文档中所述

    Really large (>50 node) Hub installations may need to increase the jetty threads by setting -DPOOL_MAX=512 (or larger) on the java command line.

    java -jar selenium-server-standalone-<version>.jar -role hub -DPOOL_MAX=512

回答by Bharath Kumar

Cucumber does not support parallel execution out of the box. I've tried, but it is not friendly.

Cucumber 不支持开箱即用的并行执行。我试过了,但它不友好。

  1. We have to use maven's capability to invoke it in parallel. Refer link
  2. Also there is a github project which uses custom plugin to execute in parallel. Refer cucumber-jvm-parallel-plugin
  1. 我们必须使用 maven 的能力来并行调用它。参考链接
  2. 还有一个 github 项目,它使用自定义插件并行执行。参考黄瓜-jvm-parallel-plugin

回答by Krishnan Mahadevan

If all you are expecting is to be able to run multiple features in parallel, then you can try doing the following :

如果您期望的是能够并行运行多个功能,那么您可以尝试执行以下操作:

  • Duplicate the class AbstractTestNGCucumberTestsin your test project and set the attribute parallel=trueto the @DataProviderannotated method.

Since the default dataprovider-thread-countfrom TestNG is 10and now that you have instructed TestNG to run featuresin parallel, you should start seeing your feature files get executed in parallel.

由于dataprovider-thread-countTestNG的默认设置是10,现在您已经指示 TestNGfeatures并行运行,您应该开始看到您的功能文件并行执行。

But I understand that Cucumber reporting is inherently not thread safe, so your reports may appear garbled.

但是我知道 Cucumber 报告本质上不是线程安全的,因此您的报告可能会出现乱码。

回答by user861594

To take maximum advantage of TestNG you can use Testng's third party extension QAFframework. It supports multiple bdd syntaxincluding gherkin using GherkinFactory. While using BDD with QAF, you can take advantage of each TestNG features, including data-providers, parallel execution configuration in different ways (groups/tests/methods), TestNG listeners.

为了最大限度地利用 TestNG,您可以使用 Testng 的第三方扩展QAF框架。它支持多种bdd 语法,包括使用GherkinFactory 的小黄瓜。在将 BDD 与 QAF 结合使用时,您可以利用每个 TestNG 功能,包括数据提供者、不同方式(组/测试/方法)的并行执行配置、TestNG 侦听器。

QAF considers each scenario as TestNG test and Scenario Outline as TestNG data-driven test. As qaf provides driver management and resource management in-built, you don't need to write single line of code for driver management or resource management. All you need to do is create TestNG xml configuration file as per your requirement either to run parallel methods (scenarios) or groups or xml test on one or more browser.

QAF 将每个场景视为 TestNG 测试,将场景大纲视为 TestNG 数据驱动测试。由于 qaf 提供了内置的驱动程序管理和资源管理,您不需要为驱动程序管理或资源管理编写一行代码。您需要做的就是根据您的要求创建 TestNG xml 配置文件,以便在一个或多个浏览器上运行并行方法(场景)或组或 xml 测试。

It enables different possible configuration combinations. Below is the xml configuration to address this questionwhich will run scenarios in two browsers and in parallel. You can configure number of threads for each browser as standard TestNG xml configuration as well.

它支持不同的可能配置组合。下面是解决这个问题的 xml配置,它将在两个浏览器中并行运行场景。您也可以将每个浏览器的线程数配置为标准 TestNG xml 配置。

<suite name="AUT Test Automation" verbose="0"  parallel="tests">
<test name="Test-on-chrome">
   <parameter name="scenario.file.loc" value="resources/features" />
   <parameter name="driver.name" value="chromeDriver" />           
   <classes>
      <class name="com.qmetry.qaf.automation.step.client.gherkin.GherkinScenarioFactory" />
   </classes>
</test>

<test name="Test-on-FF">
   <parameter name="scenario.file.loc" value="resources/features" />
   <parameter name="driver.name" value="firefoxDriver" />           
   <classes>
      <class name="com.qmetry.qaf.automation.step.client.gherkin.GherkinScenarioFactory" />
   </classes>
</test>
</suite>

More over the latest BDDTestFactory2supports syntaxthat is derived from QAF BDD, Jbehave and gherkin. It supports meta-data from qaf bdd as tags and examples from gherkin. You can take benefit of inbuilt data-providersto provide test data in XML/JSON/CSV/EXCEL/DB using meta-data in BDD.

更多来自 QAF BDD、Jbehave 和小黄瓜的最新BDDTestFactory2支持语法。它支持来自 qaf bdd 的元数据作为标签和来自小黄瓜的示例。您可以利用内置的数据提供程序使用 BDD 中的元数据提供 XML/JSON/CSV/EXCEL/DB 中的测试数据。