Java 在Cucumber中,是否可以通过编程方式获取正在执行的当前步骤?

Java 在Cucumber中,是否可以通过编程方式获取正在执行的当前步骤?,java,cucumber,Java,Cucumber,可以使用getName()函数检索场景名称。是否有一种方法也可以获得正在执行的步骤(在Java中)?我们预计将在日志记录和报告中使用此功能 因此,对于上述场景,我在我的网站上将在执行相应的步骤定义时返回。您是否询问是否可以获得一些日志记录,表明在我输入有效凭据时执行了步骤 如果是,答案是肯定的 Cucumber本身没有日志的概念,因此您必须添加自己喜欢的日志框架。因为Cucumber不知道如何通过您最喜欢的日志框架进行日志记录,所以您必须在Java中实现的每个步骤中添加日志语句 我从来没有看到自

可以使用
getName()
函数检索场景名称。是否有一种方法也可以获得正在执行的步骤(在
Java
中)?我们预计将在日志记录和报告中使用此功能


因此,对于上述场景,
我在我的网站上
将在执行相应的步骤定义时返回。

您是否询问是否可以获得一些日志记录,表明在我输入有效凭据时执行了步骤

如果是,答案是肯定的

Cucumber本身没有日志的概念,因此您必须添加自己喜欢的日志框架。因为Cucumber不知道如何通过您最喜欢的日志框架进行日志记录,所以您必须在Java中实现的每个步骤中添加日志语句

我从来没有看到自己需要记录日志。Maven的执行日志,或者您正在使用的任何构建工具,对我来说已经足够长时间了


这些报告包括执行的步骤,以涵盖该案例。

作为一名新手,我不允许发表评论,因此这里有一些信息,假设您使用的是jvm

简而言之,不,Cumber本身没有读取步骤名称的选项。您可以使用方法名称来标识调用了什么

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

或者,junit或testng之类的测试框架可以让您访问执行细节——类似这样:


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

您可以添加如下步骤

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
并在需要登录时重复此步骤


您必须将包含步骤定义的类放入每个需要登录的运行程序使用的包中。

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

When I log in with the user 'user' and the password 'password'
转化为

Given I am on my website
步骤定义将实际接受一个与步骤对应的字符串参数

'Given I am on my website'

我认为CucumberWithSerentity寄存器是存储当前步骤名称的侦听器

在您的测试跑步者中尝试以下操作:

    @And("(.*)") //plus something specific to map step
    public void Initialization(String step) throws Exception {
            //do something with step
    }
然后在你的步骤中:

//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();

net.serenity-bdd
宁静核心
${serenity.version}
这些挂钩将有助于:

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

我也有同样的问题。我试图使用rs79的答案,但要么我不知道我在用它做什么,要么它不起作用。Java给了我一个“含糊不清的步骤定义异常”之类的东西。所以我用了另一种方式。如果您有大量步骤定义,则需要做一点工作,但它可以工作并且非常简单:

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

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

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

只需将此留在此处供将来参考

Cucumber的当前版本(4.2.5)具有BeforeStep钩子,但仅提供对当前运行场景的访问

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

@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
}
@BeforeStep
public void beforeStep(场景scn)引发异常{
currentStepIndex++;
字段testCaseField=scn.getClass().getDeclaredField(“testCase”);
testCaseField.setAccessible(true);
TestCase tc=(TestCase)testCaseField.get(scn);
字段testSteps=tc.getClass().getDeclaredField(“testSteps”);
testSteps.setAccessible(true);
List teststeps=tc.getTestSteps();
试一试{
PickleStepTestStep pts=(PickleStepTestStep)teststeps.get(currentStepIndex);
getLog().info(“##########################”;
getLog().info(“步骤”);
getLog().info(pts.getStepText());
getLog().info(“##########################”;
currentStepIndex++;
}捕获(异常忽略){
}
}
唯一的缺点是,您需要类级别的int currentStepIndex,并且需要在
@BeforeStep
之前或
@BeforeStep
之前添加1


请注意在Cucumber的未来版本中使用这种类型的反射可能会失败,因为Cucumber团队可以决定更改其内部结构。

我使用@BeforeStep和@AfterStep解决了这个问题。这是一个有点黑客,所以使用它只有当你知道你在做什么

@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) {
    }
}
public类stepdefbeginedlogger{
private int currentStepDefinex=0;
@先于
public void doSomethingBeforeStep(场景)引发异常{
字段f=scenario.getClass().getDeclaredField(“testCase”);
f、 setAccessible(true);
TestCase r=(TestCase)f.get(场景);
//您需要在挂钩之前/之后进行筛选
List stepDefs=r.getTestSteps()
.stream()
.filter(PickleStepTestStep的x->x实例)
.map(x->(PickleStepTestStep)x)
.collect(Collectors.toList());
//此对象现在保存有关当前步骤定义的信息
//如果您使用的是pico容器
//只需将其存储在世界状态对象中的某个位置
//并使其在步骤定义中可用。
PickleStepTestStep currentStepDef=stepDefs
.get(currentStepDefinex);
}
@后步骤
公共无效doSomethingAfterStep(场景){
CurrentStepDefinitex+=1;
}

}

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

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;
}
结果:

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

下面是一个处理框架更改的更新。“testCase”字段隐藏在“委托”下。我使用io.cucumber.java版本5.7.0实现了这一点

myAnnotation=@cucumber.api.java.en.Given(timeout=0, value=^User is in portal page$)
公共字符串getStepText(io.cucumber.java.Scenario){
字符串currentStepDescr=null;
//跟踪CurrentStepDefinex的值
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 ;
       }
<!-- 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>