Возможно ли выполнять тесты Cucumber несколько раз на основе тегов?

#java #selenium-webdriver #cucumber #testng #cucumber-java

#java #selenium-webdriver #cucumber #testng #cucumber-java

Вопрос:

При условии, что у меня есть следующий файл функций с двумя сценариями, которые имеют разные теги, такие как приведенные ниже:

 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"
  

И у меня также есть следующие Hooks , ChromeWebController , HomeSteps amp; RunCucumberTest классы, можно ли запускать сценарии несколько раз на разных устройствах. Например, может ли сценарий с @Desktop , @Tablet amp; @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.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. Вы пробовали использовать несколько бегунов с tags опцией, установленной для каждого типа устройства. tags = @desktop и т.д. и т.п.

2. @Grasshopper Это хороший крик. Я не уверен, почему я не подумал попробовать это! Я расскажу об этом в ближайшее время и сообщу вам о результатах.

3. @Grasshopper Я пробовал это, проблема, с которой я столкнулся, заключается в том, что при настройке тегов для выполнения на планшете или мобильном устройстве он по-прежнему передает Desktop в chromeWebController.setDeviceType (Collection<String> scenarioTags), поскольку первый тег — Desktop в файле функций

4. Вам также необходимо изменить хук Before, добавив фильтр тегов в аннотацию. В итоге у вас будет столько же Before-хуков, сколько устройств. Например, для Mobile типа перед аннотацией становится @Before("@Mobile") . В перехватчике просто жестко укажите тип устройства для отправки в setDeviceType метод. Вам нужно будет изменить setDeviceType тип аргумента, чтобы принять строку. Таким образом, cucumber должен выполнить всю работу за вас.

5. @Grasshopper Я не уверен, что я неправильно понимаю, но проблема все еще сохраняется. Я хочу, чтобы файлы функций могли иметь все три тега, если это необходимо. Например. если файл функций содержит все 3 тега, то все участники тестирования подберут этот тест. Проблема, которую я использую, @Before("Mobile") заключается в том, что если в сценарии есть все три тега @Desktop @Tablet @Mobile , то он попытается использовать все @Before перехваты

Ответ №1:

Создайте два (в основном равных устройствам) пакета для конкретного устройства.

Перехват для мобильного типа в пакете mobile

 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");
    }
}
  

Общий код клея должен храниться, скажем, в отдельном пакете stepdefs .

Соответствующим образом измените раннеры.

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


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

В основном уменьшая видимость соответствующего хука. Думаю, вам нужно будет изменить код, который инициализирует драйвер.