有可能根据标签多次执行 Cucumber 测试吗?

huangapple go评论76阅读模式
英文:

Is it possible to execute Cucumber Tests multiple times based on tags?

问题

提供我有以下的特性文件其中有两个具有不同标签的场景如下所示

```java
Feature: 主页功能
  主页的测试

@Desktop @Tablet @Mobile
Scenario: 应该显示正确的页面标题
  假设我导航到主页
  那么页面标题应该为test

@Desktop @Tablet
Scenario: 应该显示正确的正文文本
  假设我导航到主页
  那么正文文本应该为test

并且我还有以下的 HooksChromeWebControllerHomeStepsRunCucumberTest 类,是否可能在不同设备上多次运行这些场景。例如,带有 @Desktop@Tablet@Mobile 标签的场景是否可以在三个不同的设备上分别执行三次,而带有 @Desktop@Tablet 标签的场景是否可以在两个不同的设备上分别执行两次?或者这是否需要不同的方法?

package hooks;

import controllers.ChromeWebController;
import fixtures.HomePageFixture;
import io.cucumber.java.After;
import io.cucumber.java.Before;
import io.cucumber.java.Scenario;

public class Hooks {
  private final ChromeWebController chromeWebController;
  private Scenario scenario;

  public Hooks(ChromeWebController chromeWebController) {
    this.chromeWebController = chromeWebController;
  }

  @Before
  public void beforeScenarioSteps(Scenario scenario) {
    this.scenario = scenario;
    chromeWebController.setDeviceType(scenario.getSourceTagNames());
    chromeWebController.setupChromeDriver();
    scenario.log(HomePageFixture.HOME_PAGE_URL);
  }

  @After
  public void afterScenarioSteps() {
    chromeWebController.quitWebDriver();
  }
}
package controllers;

import io.github.bonigarcia.wdm.WebDriverManager;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebDriverException;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;

public class ChromeWebController {
  private WebDriver webDriver;
  private String deviceType;

  public ChromeWebController() {
  }

  public void setupChromeDriver() {
    ChromeOptions options = new ChromeOptions();
    Map<String, String> mobileEmulation = new HashMap<>();

    WebDriverManager.chromedriver().setup();

    options.addArgument("--window-size=1366,768");

    if (getDeviceType().equals("Tablet")) {
      mobileEmulation.put("deviceName", "iPad");
      options.setExperimentalOption("mobileEmulation", mobileEmulation);
    } else if (getDeviceType().equals("Mobile")) {
      mobileEmulation.put("deviceName", "iPhone X");
      options.setExperimentalOption("mobileEmulation", mobileEmulation);
    }

    this.webDriver = new ChromeDriver(options);
  }

  public WebDriver getWebDriver() {
    if (webDriver == null) {
      throw new WebDriverException("WebDriver has not been created, please ensure setupChromeDriver has been called.");
    }
    return webDriver;
  }

  public void quitWebDriver() {
    webDriver.quit();
  }

  public void setDeviceType(Collection<String> scenarioTags) {
    if (deviceType != null) {
      throw new IllegalArgumentException("deviceType can only be set once.");
    }

    var scenarioTagsToString = scenarioTags.toString();

    if (scenarioTagsToString.contains("@Desktop")) {
      deviceType = "Desktop";
    } else if (scenarioTagsToString.contains("@Tablet")) {
      deviceType = "Tablet";
    } else if (scenarioTags.toString().contains("@Mobile")) {
      deviceType = "Mobile";
    } else {
      throw new IllegalArgumentException("Desktop/Tablet/Mobile scenario tag has not been implemented in the feature file.");
    }
  }

  public String getDeviceType() {
    if (deviceType.equals("")) {
      throw new IllegalArgumentException("deviceType has not been set.");
    }

    return deviceType;
  }
}
package steps.home;

import controllers.ChromeWebController;
import fixtures.HomePageFixture;
import io.cucumber.java.en.Given;
import io.cucumber.java.en.Then;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;

public class HomeSteps{
    private final WebDriver webDriver;

    public HomeSteps(ChromeWebController chromeWebController) {
        this.webDriver = chromeWebController.getWebDriver();
    }

    @Given("I navigate to the Home page")
    public void iNavigateToTheHomePage() {
        webDriver.get(HomePageFixture.HOME_PAGE_URL);
    }

    @Then("The body text should read {string}")
    public void theBodyTextShouldRead(String expectedText) {
        String actualText = webDriver.findElement(By.id("test")).getText();

        assert (actualText).equals(expectedText);
    }
}
import io.cucumber.testng.AbstractTestNGCucumberTests;
import io.cucumber.testng.CucumberOptions;
import org.testng.annotations.DataProvider;

@CucumberOptions(publish = true)
public class RunCucumberTest extends AbstractTestNGCucumberTests {
    @Override
    @DataProvider(parallel = true)
    public Object[][] scenarios() {
        return super.scenarios();
    }
}

<details>
<summary>英文:</summary>
Providing I have the following Feature File with two scenarios that have different tags such as the below:

Feature: Home Feature
Tests for the Home page

@Desktop @Tablet @Mobile
Scenario: I should see the correct page title
Given I navigate to the Home page
Then the page title should read "test"

@Desktop @Tablet
Scenario: I should see the correct body text
Given I navigate to the Home page
Then the body text should read "test"


And I also have the following ```Hooks```, ```ChromeWebController```, ```HomeSteps``` &amp; ```RunCucumberTest``` classes, would it be possible to run the scenarios multiple times on different devices. For example, could the scenario with ```@Desktop```, ```@Tablet``` &amp; ```@Mobile``` be executed three times, once on each device, whilst, the scenario with ```@Desktop``` ```@Tablet``` be executed two times, again, once on each device? Or would this require a different approach?

package hooks;

import controllers.ChromeWebController;
import fixtures.HomePageFixture;
import io.cucumber.java.After;
import io.cucumber.java.Before;
import io.cucumber.java.Scenario;

public class Hooks {
private final ChromeWebController chromeWebController;
private Scenario scenario;

public Hooks(ChromeWebController chromeWebController) {
this.chromeWebController = chromeWebController;
}

@Before
public void beforeScenarioSteps(Scenario scenario) {
this.scenario = scenario;
chromeWebController.setDeviceType(scenario.getSourceTagNames());
chromeWebController.setupChromeDriver();
scenario.log(HomePageFixture.HOME_PAGE_URL);
}

@After
public void afterScenarioSteps() {
chromeWebController.quitWebDriver();
}
}


package controllers;

import io.github.bonigarcia.wdm.WebDriverManager;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebDriverException;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;

public class ChromeWebController {
private WebDriver webDriver;
private String deviceType;

public ChromeWebController() {
}

public void setupChromeDriver() {
ChromeOptions options = new ChromeOptions();
Map<String, String> mobileEmulation = new HashMap<>();

WebDriverManager.chromedriver().setup();
options.addArgument(&quot;--window-size=1366,768&quot;);
if (getDeviceType().equals(&quot;Tablet&quot;)) {
mobileEmulation.put(&quot;deviceName&quot;, &quot;iPad&quot;);
options.setExperimentalOption(&quot;mobileEmulation&quot;, mobileEmulation);
} else if (getDeviceType().equals(&quot;Mobile&quot;)) {
mobileEmulation.put(&quot;deviceName&quot;, &quot;iPhone X&quot;);
options.setExperimentalOption(&quot;mobileEmulation&quot;, mobileEmulation);
}
this.webDriver = new ChromeDriver(options);

}

public WebDriver getWebDriver() {
if (webDriver == null) {
throw new WebDriverException("WebDriver has not been created, please ensure setupChromeDriver has been called.");
}
return webDriver;
}

public void quitWebDriver() {
webDriver.quit();
}

public void setDeviceType(Collection<String> scenarioTags) {
if (deviceType != null) {
throw new IllegalArgumentException("deviceType can only be set once.");
}

var scenarioTagsToString = scenarioTags.toString();
if (scenarioTagsToString.contains(&quot;@Desktop&quot;)) {
deviceType = &quot;Desktop&quot;;
} else if (scenarioTagsToString.contains(&quot;@Tablet&quot;)) {
deviceType = &quot;Tablet&quot;;
} else if (scenarioTags.toString().contains(&quot;@Mobile&quot;)) {
deviceType = &quot;Mobile&quot;;
} else {
throw new IllegalArgumentException(&quot;Desktop/Tablet/Mobile scenario tag has not been implemented in the feature file.&quot;);
}

}

public String getDeviceType() {
if (deviceType.equals("")) {
throw new IllegalArgumentException("deviceType has not been set.");
}

return deviceType;

}
}


package steps.home;

import controllers.ChromeWebController;
import fixtures.HomePageFixture;
import io.cucumber.java.en.Given;
import io.cucumber.java.en.Then;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;

public class HomeSteps{
private final WebDriver webDriver;

public HomeSteps(ChromeWebController chromeWebController) {
this.webDriver = chromeWebController.getWebDriver();
}
@Given(&quot;I navigate to the Home page&quot;)
public void iNavigateToTheHomePage() {
webDriver.get(HomePageFixture.HOME_PAGE_URL);
}
@Then(&quot;The body text should read {string}&quot;)
public void theBodyTextShouldRead(String expectedText) {
String actualText = webDriver.findElement(By.id(&quot;test&quot;)).getText();
assert (actualText).equals(expectedText);
}

}


```import io.cucumber.testng.AbstractTestNGCucumberTests;
import io.cucumber.testng.CucumberOptions;
import org.testng.annotations.DataProvider;
@CucumberOptions(publish = true)
public class RunCucumberTest extends AbstractTestNGCucumberTests {
@Override
@DataProvider(parallel = true)
public Object[][] scenarios() {
return super.scenarios();
}
}

答案1

得分: 1

创建两个基本上等于设备的用于特定设备钩子的包

移动设备类型的钩子放在 `mobile` 包中

```java
package mobile;

public class MobileHook {

    @Before("@mobile")
    public void before(Scenario scenario) {
        System.out.println("MOBILE");
    }
}

平板设备类型的钩子放在 tablet 包中:

package tablet;

public class TabletHook {

    @Before("@tablet")
    public void before() {
        System.out.println("TABLET");
    }
}

通用的 Glue 代码应该放在一个单独的包中,比如 stepdefs

相应地修改运行器:

@CucumberOptions(plugin = { "summary" }, tags = "@mobile", glue = {"mobile", "stepdefs"})
public class RunCukeMobileIT

@CucumberOptions(plugin = { "summary" }, tags = "@tablet", glue = {"tablet", "stepdefs"})
public class RunCukeTabletIT

基本上是将可见性降低到相关的钩子。我猜您需要修改初始化驱动程序的代码。


<details>
<summary>英文:</summary>
Create two (basically equal to the devices) packages for device specific hook.
Hook for mobile type in package `mobile`
package mobile;
public class MobileHook {
@Before(&quot;@mobile&quot;)
public void before(Scenario scenario) {
System.out.println(&quot;MOBILE&quot;);
}
}
Hook for tablet type in package `tablet`
package tablet;
public class TabletHook {
@Before(&quot;@tablet&quot;)
public void before() {
System.out.println(&quot;TABLET&quot;);
}
}
The common glue code should be kept in a separate package say `stepdefs`.
Modify the runners accordingly.
@CucumberOptions(plugin = { &quot;summary&quot; }, tags = &quot;@mobile&quot;, glue = {&quot;mobile&quot;, &quot;stepdefs&quot;})
public class RunCukeMobileIT
@CucumberOptions(plugin = { &quot;summary&quot; }, tags = &quot;@tablet&quot;, glue = {&quot;tablet&quot;, &quot;stepdefs&quot;})
public class RunCukeTabletIT
Basically reducing the visibility to the relevant hook. Guess u will need to modify the code which initializes the driver.
</details>

huangapple
  • 本文由 发表于 2020年8月28日 00:08:00
  • 转载请务必保留本文链接:https://go.coder-hub.com/63620031.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定