将Cucumber特征中的WebElement参数传递到步骤定义

时间:2016-08-23 12:53:56

标签: java selenium selenium-webdriver cucumber cucumber-java

我试图将Cucumber特征文件中的WebElement(而不是String)传递给它的相应步骤定义。

Scenario: Test
    Given I want to click "myWebElement"

相应的步骤定义为:

@Given("^I want to click (.*)$")
    public void Test(WebElement we) {
        we.click();
    }

在运行时,我得到以下跟踪:

cucumber.runtime.CucumberException: Don't know how to convert ""myWebElement"" into org.openqa.selenium.WebElement.
Try writing your own converter:

@cucumber.deps.com.thoughtworks.xstream.annotations.XStreamConverter(WebElementConverter.class)
public class WebElement {}

    at cucumber.runtime.ParameterInfo.convert(ParameterInfo.java:150)
    at cucumber.runtime.StepDefinitionMatch.transformedArgs(StepDefinitionMatch.java:68)
    at cucumber.runtime.StepDefinitionMatch.runStep(StepDefinitionMatch.java:37)
    at cucumber.runtime.Runtime.runStep(Runtime.java:299)
    at cucumber.runtime.model.StepContainer.runStep(StepContainer.java:44)
    at cucumber.runtime.model.StepContainer.runSteps(StepContainer.java:39)
    at cucumber.runtime.model.CucumberScenario.run(CucumberScenario.java:44)
    at cucumber.runtime.model.CucumberFeature.run(CucumberFeature.java:165)
    at cucumber.api.testng.TestNGCucumberRunner.runCucumber(TestNGCucumberRunner.java:63)
    at cucumber.api.testng.AbstractTestNGCucumberTests.feature(AbstractTestNGCucumberTests.java:21)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:80)
    at org.testng.internal.Invoker.invokeMethod(Invoker.java:714)
    at org.testng.internal.Invoker.invokeTestMethod(Invoker.java:901)
    at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:1231)
    at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:127)
    at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:111)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at java.lang.Thread.run(Thread.java:744)

是否有可以为这样的"转换器"?

编写的功能

感谢。

3 个答案:

答案 0 :(得分:3)

首先,您需要问问自己为什么要将WebElement作为参数传递给BDD框架。 BDD测试框架通常用于验收测试,因此参数应该是利益相关者可以理解的。

现在,为了得到答案,Cucumber使用所谓的变形金刚来实现这一目标。取自Cucumber文档:

  

public abstract class Transformer extends Object implements   cucumber.deps.com.thoughtworks.xstream.converters.SingleValueConverter   允许将步骤定义参数转换为自定义类型,   让您完全控制该类型的实例化方式。

     

考虑以下Gherkin步骤:

     

鉴于今天的日期是" 10/03 / 1985"举个例子,我们假设我们想要   黄瓜改造子串" 10/03 / 1985"进入一个实例   org.joda.time.LocalDate类:

 @Given("today's date is \"(.*)\"")
 public void todays_date_is(LocalDate d) {
 }   If the parameter's class has a constructor with a single String or Object argument, then Cucumber will instantiate it without
     

任何进一步的麻烦。但是,在这种情况下可能不会给你什么   你要。根据您的区域设置,日期可能是10月3日或3月10日!

     

这是您可以使用自定义变压器的时候。你也必须这样做   如果你的参数类没有一个构造函数   字符串或对象参数。对于JODA时间示例:

 @Given("today's date is \"(.*)\"")
 public void todays_date_is(@Transform(JodaTimeConverter.class) LocalDate d) {
 }   And then a JodaTimeConverter class:


 public static class JodaTimeConverter extends Transformer<LocalDate> {
     private static DateTimeFormatter FORMATTER = DateTimeFormat.forStyle("S-");

     @Override
     public LocalDate transform(String value) {
         return FORMATTER.withLocale(getLocale()).parseLocalDate(value);
     }
 }   An alternative to annotating parameters with Transform is to annotate your class with XStreamConverter:

 @XStreamConverter(MyConverter.class)
 public class MyClass {
 }   This will also enable a DataTable to be transformed to a List<MyClass;>

我还没有用WebElement类型尝试过,但原理是一样的。 您可以找到更多信息here

答案 1 :(得分:0)

我知道这个问题是针对Java的,但这是我为C#中的相同要求所做的工作。我只是为了帮助来到这里的人为同一问题在C#中寻找解决方案

您可以在c#黄瓜/ specflow中使用[StepArgumentTransformation]来实现

  Scenario Outline: examples with step argument
  Given we have '<Webelements>'

  Examples:
  | Webelements | 
  |     Gmail   |

步骤定义为:

  using TechTalk.SpecFlow;
  using OpenQA.Selenium.Chrome;
  using OpenQA.Selenium.Support.UI;
  using NUnit.Framework;

[Binding]
   public class Browser
  {
     private readonly BrowserDriver _browserDriver;
     public static  OpenQA.Selenium.IWebDriver driver ;

      public Browser(BrowserDriver browserDriver, FeatureContext featureContext)
    {
        _browserDriver = browserDriver;  //your chrome driver
        driver = _browserDriver._driver;
        _featureContext = featureContext;
        _featureContext.Add("driver", driver);
    }

     [Given(@"we have '(.*)'")] 

    public void webelements(ChromeWebElement o)
    {
       Assert.False(o.Displayed);
    }

    [StepArgumentTransformation]
      public ChromeWebElement convertToWebElement(string c)
      {
        ChromeDriver parent = _featureContext.Get<ChromeDriver>("driver");
        return new ChromeWebElement(parent, c);
    }  

很明显,您得到结果element is not attached to the page document,因为我只是将Gmail元素用于测试目的

答案 2 :(得分:-1)

实现此目的的标准方法是提供定位器或定位器的引用作为step参数,并在step中使用create元素。例如,使用qaf,您可以执行以下步骤:

    import static com.qmetry.qaf.automation.ui.webdriver.ElementFactory.$;
    ...

    @Given("^I want to click (.*)$")
    public void click(String eleLoc) {
        $("eleLoc").click();
    }

    //blow is example using qaf step annotation
    //that doesn't need regex...
    @QAFTestStep(description="I want to click {element}")
    public void click(String eleLoc) {
        $("eleLoc").click();
    }

可以在特征文件中调用以下步骤:

Scenario: Test
    Given I want to click "name=q"

如果您使用的是locator repository,则可能如下所示:

mypage_locators.properties

page.myWebElement=name=q 
#add other locators for this page

下面的self descriptive value是上面相同的定位符

page.myWebElement={"locator":"name=q", "desc":"search text box on search page"}

可以在特征文件中调用以下步骤:

Scenario: Test
    Given I want to click "page.myWebElement"

您可以使用或引用适用于webmobileperfectoweb-services的内置步骤,也可以使用自定义步骤实现。