在Cucumber中,是否可以以编程方式获取当前步骤?

时间:2016-09-23 15:25:44

标签: java cucumber

Scenario: As a user, I want to login to the system
Given I am on my website
When I enter valid credentials
Then I am taken to the home page

可以使用getName()函数检索方案名称。有没有办法让步骤被执行(在Java)?我们预计会在记录和报告中使用它。

因此,对于上面的场景,在执行相应的步骤定义时将返回I am on my website

11 个答案:

答案 0 :(得分:2)

我们通过将整个步骤作为参数包装到“步骤定义”中来解决了这个问题。换句话说,步骤

Given I am on my website

转换为

'Given I am on my website'

步骤定义实际上将接受与步骤

对应的字符串参数
    @And("(.*)") //plus something specific to map step
    public void Initialization(String step) throws Exception {
            //do something with step
    }

答案 1 :(得分:2)

我认为CucumberWithSerenity注册了一个存储当前步骤名称的监听器。

在Test-Runner中尝试:

//import net.serenitybdd.cucumber.CucumberWithSerenity;
@RunWith(CucumberWithSerenity.class)
@CucumberOptions(...

然后进入你的步骤:

//import net.thucydides.core.model.TestStep;
//import net.thucydides.core.steps.StepEventBus;
if (!StepEventBus.getEventBus().isBaseStepListenerRegistered()) {
    return "Unknown"; // CucumberWithSerenity is required.
} 
String currentStepDescr = StepEventBus.getEventBus().getCurrentStep()
    .transform(TestStep::getDescription)
    .get();

相关性:

<dependency>
    <groupId>net.serenity-bdd</groupId>
    <artifactId>serenity-core</artifactId>
    <version>${serenity.version}</version>
</dependency>

答案 2 :(得分:1)

这些钩子将帮助:

@BeforeStep
public void beforeStep(Scenario scenario){
  System.out.println(scenario.toString());
}

@AfterStep
public void afterStep(Scenario scenario){
  System.out.println(scenario.toString());
}

答案 3 :(得分:1)

这是处理框架更改的更新。 “ testCase”字段隐藏在“代表”下方。我在io.cucumber.java版本5.7.0中使用了此功能

public String getStepText(io.cucumber.java.Scenario scenario){      
    String  currentStepDescr = null;

    //value currentStepDefIndex is tracked in the another class
    int currentStepDefIndex = OtherClass.getStepIndex();

    Field f = scenario.getClass().getDeclaredField("delegate");
    f.setAccessible(true);
    TestCaseState tcs = (TestCaseState) f.get(scenario);

    Field f2 = tcs.getClass().getDeclaredField("testCase");
    f2.setAccessible(true);
    TestCase r = (TestCase) f2.get(tcs);

        List<PickleStepTestStep> stepDefs = r.getTestSteps()
                .stream()
                .filter(x -> x instanceof PickleStepTestStep)
                .map(x -> (PickleStepTestStep) x)
                .collect(Collectors.toList());


        PickleStepTestStep currentStepDef = stepDefs
                .get(currentStepDefIndex);
        currentStepDescr = currentStepDef.getStep().getText();
        currentStepDefIndex += 1;
        OtherClass.setStepIndex(currentStepDefIndex);
         return currentStepDescr ;
       }

下面是我pom.xml中的依赖项

<!-- https://mvnrepository.com/artifact/io.cucumber/cucumber-core -->
        <dependency>
            <groupId>io.cucumber</groupId>
            <artifactId>cucumber-core</artifactId>
            <version>5.7.0</version>
        </dependency>


        <!-- https://mvnrepository.com/artifact/io.cucumber/cucumber-testng -->
        <dependency>
            <groupId>io.cucumber</groupId>
            <artifactId>cucumber-testng</artifactId>
            <version>5.7.0</version>
        </dependency>


        <!-- https://mvnrepository.com/artifact/io.cucumber/cucumber-java -->
        <dependency>
            <groupId>io.cucumber</groupId>
            <artifactId>cucumber-java</artifactId>
            <version>5.7.0</version>
        </dependency>


        <!-- https://mvnrepository.com/artifact/io.cucumber/cucumber-jvm-deps -->
        <dependency>
            <groupId>io.cucumber</groupId>
            <artifactId>cucumber-jvm-deps</artifactId>
            <version>1.0.6</version>
            <scope>provided</scope>
        </dependency>

答案 4 :(得分:0)

您是否询问是否可以获得一些表明步骤When I enter valid credentials已执行的日志记录?

如果是这样,答案是肯定的。

黄瓜这样没有记录的概念所以你必须添加自己喜欢的日志框架。由于Cucumber不知道如何记录您喜欢的日志框架,因此您必须在用Java实现的每个步骤中添加一个日志语句。

我从未见过需要自己记录。 Maven的执行日志,或者你正在使用的任何构建工具,对我来说已经足够了很长时间。

报告包括已执行的步骤,以便涵盖案例。

答案 5 :(得分:0)

作为一个新手,我不允许发表评论,所以这里有一些信息,假设你使用的是cucumber-jvm。

简短回答,不,黄瓜本身没有选择读取步骤名称的选项。您可以使用方法名称来标识所调用的内容。

此外,@ BEFORE STEP / @AFTER STEP标签尚不可用,因此您必须为每个步骤定义调用。

https://github.com/cucumber/cucumber-jvm/pull/838#issuecomment-234110573

或像junit或testng这样的测试框架可以让你访问执行细节 - 如下所示: http://junit.org/junit4/javadoc/4.12/org/junit/rules/TestWatcher.html

如果您确实只需要用于报告目的的步骤名称,则可以简单地解析测试框架生成的xml报告。

答案 6 :(得分:0)

你可以添加一个像

这样的步骤
When I log in with the user 'user' and the password 'password'

并在需要登录时重复此步骤

您必须将包含步骤定义的类放在每个需要登录的Runner使用的包中。

答案 7 :(得分:0)

我有同样的问题。我试图使用rs79的答案,但是我不知道我实际上在用它做什么,或者它不起作用。 Java给我一个“ AmbiguousStepDefinitionException”或类似的东西。所以我做了另一种方式。如果您有很多步骤定义,则需要花费一些时间,但它确实有效并且非常简单:

@Then(value = "^The page should navigate to url \"([^\"])\"$", timeout = MAX_TIME)
public void the_page_should_navigate_to_url(String url) {
    //below I use a custom class with a static method setStepName() which just sets a string field in the class
    CustomClass.setStepName("Then The page should navigate to url " + url);
    //Assert
}

现在,您无需任何复杂的工具即可访问步骤名称。只需使用get方法即可访问自定义类中的step变量。希望有帮助。

答案 8 :(得分:0)

只需将其留在这里以备将来参考...

当前版本的Cucumber(4.2.5)具有BeforeStep挂钩,但仅提供对当前运行方案的访问。​​

我提取当前步骤的操作是使用反射来访问该场景中的步骤;

@BeforeStep
public void beforeStep(Scenario scn) throws Exception {
    currentStepIndex++;

    Field testCaseField = scn.getClass().getDeclaredField("testCase");
    testCaseField.setAccessible(true);

    TestCase tc = (TestCase) testCaseField.get(scn);
    Field testSteps = tc.getClass().getDeclaredField("testSteps");
    testSteps.setAccessible(true);

    List<TestStep> teststeps = tc.getTestSteps();
    try {
        PickleStepTestStep pts = (PickleStepTestStep) teststeps.get(currentStepIndex);
        getLog().info("########################");
        getLog().info("##########STEP##########");
        getLog().info(pts.getStepText());
        getLog().info("########################");
        currentStepIndex++;
    } catch (Exception ignore) {
    }
}

唯一的缺点是,您需要在类级别使用int currentStepIndex,并且需要在每个@Before@BeforeStep上加1。

请警告,由于Cucumber团队可以决定更改其内部结构,因此在将来的Cucumber版本中使用这种类型的反射可能无法正常工作。

答案 9 :(得分:0)

我使用@BeforeStep和@AfterStep解决了它。这有点hacky,所以只有在知道自己在做什么的情况下才使用它。

public class StepDefBeginEndLogger {

private int currentStepDefIndex = 0;

@BeforeStep
public void doSomethingBeforeStep(Scenario scenario) throws Exception {

    Field f = scenario.getClass().getDeclaredField("testCase");
    f.setAccessible(true);
    TestCase r = (TestCase) f.get(scenario);

    //You need to filter out before/after hooks
    List<PickleStepTestStep> stepDefs = r.getTestSteps()
            .stream()
            .filter(x -> x instanceof PickleStepTestStep)
            .map(x -> (PickleStepTestStep) x)
            .collect(Collectors.toList());


    //This object now holds the information about the current step definition
    //If you are using pico container 
    //just store it somewhere in your world state object 
    //and to make it available in your step definitions.
    PickleStepTestStep currentStepDef = stepDefs
            .get(currentStepDefIndex);
}

@AfterStep
public void doSomethingAfterStep(Scenario scenario) {
    currentStepDefIndex += 1;
}

}

答案 10 :(得分:0)

使用自反射抓取注释对我来说似乎更简单:

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;

@When("^User enters username and password$")
public void userEntersUsernameAndPassword() throws Throwable{
    Method callingMethod = new Object() {} .getClass() .getEnclosingMethod();
    Annotation  myAnnotation = callingMethod.getAnnotations()[0];   
    System.out.println("myAnnotation=" + myAnnotation);

结果:

myAnnotation=@cucumber.api.java.en.Given(timeout=0, value=^User is in portal page$)