Extracting Cucumber Step name at runtime

2019-02-26 23:44发布

问题:

I am trying to find out if there is an option to figure out the cucumber step currently getting executed, I am trying to perform certain action depending on the step name.

I can see StepDefinitionMatch class gets the steps, but I am not sure how can I access the steps at runtime. Any help? Adding a snapshot of the call stack if that helps.

public StepDefinitionMatch(List<Argument> arguments, StepDefinition stepDefinition, String featurePath, Step step, LocalizedXStreams localizedXStreams) {
    super(arguments, stepDefinition.getLocation(false));
    this.stepDefinition = stepDefinition;
    this.featurePath = featurePath;
    this.step = step;
    this.localizedXStreams = localizedXStreams;
}

回答1:

Just wait for Cucumber 3.0.0 release, you can access the step names using @AfterStep and @BeforeStep Annotations.

https://github.com/cucumber/cucumber-jvm/blob/master/CHANGELOG.md https://github.com/cucumber/cucumber-jvm/pull/1323

Thanks to Aniket (Coding-Yogi) https://github.com/coding-yogi



回答2:

One way to get hold of the runtime variables is to use the plugin option. Though it seems like an abuse of the Reporter interface to access the StepDefinitionMatch variable for Cucumber version 1.2.5.

For this create a custom class which implements the Reporter interface.

public class CustomFormatter implements Reporter{

    public  CustomFormatter() { }

    @Override
    public void before(Match match, Result result) {}

    @Override
    public void result(Result result) {}

    @Override
    public void after(Match match, Result result) {}

    @Override
    public void match(Match match) {
        ThreadLocalStepDefinitionMatch.set((StepDefinitionMatch)match);
    }

    @Override
    public void embedding(String mimeType, byte[] data) {}

    @Override
    public void write(String text) {}
}

The ThreadLocal class to store the StepDefinitionMatch variable.

public class ThreadLocalStepDefinitionMatch {

    private static final ThreadLocal<StepDefinitionMatch> threadStepDefMatch = new InheritableThreadLocal<StepDefinitionMatch>();

    private ThreadLocalStepDefinitionMatch() {
    }

    public static StepDefinitionMatch get() {
        return threadStepDefMatch.get();
    }

    public static void set(StepDefinitionMatch match) {
        threadStepDefMatch.set(match);
    }

    public static void remove() {
        threadStepDefMatch.remove();
    }
}

The declaration for custom plugin in the runner class

@CucumberOptions(plugin = { "pretty", "html:report", "json:reports.json",
        "rerun:target/rerun.txt", "cusform.CustomFormatter" }

Finally accessing the StepDefinitionMatch variable in the step definition class

@When("^user gets count from \"([^\"]*)\"$")
    public void userGetsCountFromAndStores(String arg) {
        StepDefinitionMatch match = ThreadLocalStepDefinitionMatch.get();
        System.out.println(match.getStepName());
        System.out.println(match.getPattern());
        System.out.println(match.getArguments());
    }

The console output gives the following

user gets count from "Car1"
^user gets count from "([^"]*)"$
[Car1]

You are using a pretty old Cucumber version, if you upgrade to Cucumber 2 there will be some changes. The StepDefinitionMatch replaced by PickleTestStep. The declaration in the runner remains the same. The ThreadLocal class change the stored class to PickleTestStep.

The custom formatter becomes

public class CustomFormatter implements Formatter {

    public CustomFormatter() {}

    private EventHandler<TestStepStarted> stepStartedHandler = new EventHandler<TestStepStarted>() {
        @Override
        public void receive(TestStepStarted event) {
            handleTestStepStarted(event);
        }
    };

    @Override
    public void setEventPublisher(EventPublisher publisher) {
        publisher.registerHandlerFor(TestStepStarted.class, stepStartedHandler);
    }

    private void handleTestStepStarted(TestStepStarted event) { 
        if(event.testStep instanceof PickleTestStep) {
            ThreadLocalPickleStep.set((PickleTestStep)event.testStep);
        }

    }
}

Accessing the StepDefinitionMatch variable in the step definition class

@When("^user gets count from \"([^\"]*)\"$")
    public void userGetsCountFromAndStores(String arg) {

        System.out.println(ThreadLocalPickleStep.get().getStepText());
        System.out.println(ThreadLocalPickleStep.get().getPattern());
        System.out.println(ThreadLocalPickleStep.get().getDefinitionArgument());
    }

The output is the same as before.