-
-
Notifications
You must be signed in to change notification settings - Fork 2k
Description
cucumber-java8 allows step definitions to be defined as lambda's. This is really nice because it removes the need to type your step definition twice as you would with cucumber-java. So there is a good reason to use lambda's to define step definitions.
Compare:
Given("A gherkin and a zukini", () -> {
});
@Given("A gherkin and a zukini")
public void a_gherkin_and_zukini(){
}Unfortunately with cucumber-java8 lambda's must be defined in the constructor of a step definition class. As a result we can not know which step definitions are defined until a Cucumber scenario has started and all world objects are instantiated. This makes it impossible to discover, cache and validate step definitions up front, preventing us from making Cucumber more efficient (#2035).
public class StepDefinitions {
public StepDefinitions(){
Given("A gherkin and a zukini", () -> {
});
}
}Additionally Cucumber uses typetools to determine the type of lambda parameters. This requires the use of of Unsafe to fish in the constant pool. This is a non-trivial process and Cucumber currently uses typetools to facilitate this. However because this fundamentally depends on unsafe operation it is not guaranteed to work in the long run.
Requested solution
- Implement
cucumber-lambdaas an alternative forcucumber-java8that uses a DSL to build step definitions. Because this DSL is created in a static field it can be discovered in the same waycuucmber-javadiscovers step definitions and avoids the issues ofcucumber-java8.
public class CucumberLambdaStepDefinitions {
@Glue
public static CucumberLambda glue = CucumberLambda
.using(World.class)
.step("A gherkin and a zukini", (World world) -> () -> {
world.setGherkins(1);
world.setZukinis(1);
})
.step("{int} gherkin(s) and {int} zukini(s)", (World world) -> (int gherkins, int zukinis) -> {
world.setGherkins(gherkins);
world.setZukinis(zukinis);
});
// repeat for hooks, parameter types and data table types, ect
// hooks should be named beforeAll, beforeEach, beforeStep.-
Avoid the use of
typetoolswhere possible by specifying all parameter types -
The
Worldobject is created using DI as usual. Consider the possibility of defining steps/hooks using multiple objects.
CucumberLambda
.using(GherkinPatch.class, ZukiniPatch.class)
.step("A gherkin and a zukini", (gherkinPatch, zukiniPatch) -> () -> {
// tend to the vegetable garden here
});Out of scope
- Generate localized vairations of the DSL that use Given/When/Then.
@Glue
public static CucumberLambda glue = io.cucumber.lambda.en.CucumberLambda
.using(World.class)
.given("A gherkin and a zukini", (World world) -> () -> {
world.setGherkins(1);
world.setZukinis(1);
})
.when("{int} gherkin(s) and {int} zukini(s)", (World world) -> (int gherkins, int zukinis) -> {
world.setGherkins(gherkins);
world.setZukinis(zukinis);
});
// ect.