Consider cucumber-java-lambda as a replacement for cucumber-java8
See original GitHub issuecucumber-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-lambda
as an alternative forcucumber-java8
that uses a DSL to build step definitions. Because this DSL is created in a static field it can be discovered in the same waycuucmber-java
discovers 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
typetools
where possible by specifying all parameter types -
The
World
object 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.
Issue Analytics
- State:
- Created 2 years ago
- Reactions:3
- Comments:29 (23 by maintainers)
Top GitHub Comments
I don’t understand a word of what you are saying.
Some more sketches in https://github.com/mpkorstanje/cucumber-lambda-proposals
There are 4 options to consider: