In Cucumber, is it possible to programmatically get the current step being executed?

后端 未结 11 2447
清歌不尽
清歌不尽 2020-12-04 00:22
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

The sce

相关标签:
11条回答
  • 2020-12-04 00:54

    I solved it using @BeforeStep & @AfterStep. It is a bit hacky, so use it only if you are know what you are doing.

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

    }

    0 讨论(0)
  • 2020-12-04 00:57

    Just leaving this here for future reference...

    The current version of Cucumber (4.2.5) has the BeforeStep hook, but only provides access to the current running scenario.

    What I did to extract the current step, was using reflection to access the steps within that scenario;

    @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) {
        }
    }
    

    The only downside is, that you require a int currentStepIndex at class level, and need to add 1 with every @Before or @BeforeStep.

    BE WARNED that the use of this type of reflection may fail to work in future releases of Cucumber, as the Cucumber team can decide to change their internals.

    0 讨论(0)
  • 2020-12-04 00:58

    Here's an update to handle the framework changes. The "testCase" field is hidden under the "delegate". I got this working with io.cucumber.java version 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 ;
           }
    

    Below are the dependencies in my 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>
    
    0 讨论(0)
  • 2020-12-04 00:58

    I had this same question. I attempted to use rs79's answer but either I don't know what I'm actually doing with it or it doesn't work. Java gives me an "AmbiguousStepDefinitionException" or something like that. So I did it a different way. It takes a little work if you have a slew of step definitions but it works and is pretty simple:

    @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
    }
    

    Now you have access to the step name without needing any kind of complicated tool. Just use a get method to access the step variable in your custom class. Hope that helps.

    0 讨论(0)
  • 2020-12-04 01:00

    These hooks will help:

    @BeforeStep
    public void beforeStep(Scenario scenario){
      System.out.println(scenario.toString());
    }
    
    @AfterStep
    public void afterStep(Scenario scenario){
      System.out.println(scenario.toString());
    }
    
    0 讨论(0)
  • 2020-12-04 01:05

    Being a newbie m not allowed to comment so here is some info, assuming you are using cucumber-jvm.

    Short answer, No, Cucumber by itself doesnt have the option to read step names. You could use the method names to identify what was called.

    Also, @BEFORE STEP / @AFTER STEP tags are not yet available so you will have to define the call for each step.

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

    or the testing framework like junit or testng could let you access the execution details - something like this: http://junit.org/junit4/javadoc/4.12/org/junit/rules/TestWatcher.html.

    And if you really need the step names only for reporting purposes, you can simply parse the xml report that the testing framework generates.

    0 讨论(0)
提交回复
热议问题