Cucumber is a nice framework coming from ruby world to do Behavior Driven Development (BDD). It got some nice extensions for others language in cucumber-jvm project.
However it was not integrated with Arquillian so you still had to do all the integration logic yourself.
That’s why cukespace was created. The idea is to integrate both frameworks to get the best of each.
In practice you need to bring back cukespace-core (and its dependencies) in your project (next snippet is for maven):
<dependency> <groupId>com.github.cukespace</groupId> <artifactId>cukespace-core</artifactId> <version>1.0.0.Beta3-SNAPSHOT</version> <scope>test</scope> <exclusions> <exclusion> <groupId>org.jboss.shrinkwrap</groupId> <artifactId>shrinkwrap-api</artifactId> </exclusion> </exclusions> </dependency>
PS: while it is not deployed on a public maven repo you’ll have to build it from sources (a simple mvn clean install -Dmaven.test.skip=true will do the job).
Then you can define your test classes.
To do so you simply need to follow the following steps:
- create a test class
- add @RunWith(ArquillianCucumber.class) on it (ArquillianCucumber replaces Arquillian runner)
- write a standard Arquillian @Deployment method (@Deployment public static WebArchive war() { … })
- write your feature in a feature file in the same package as your test class and with the same name as your test class without the Test/IF suffix and replacing uppercases by ‘-‘ + the lowercase of the letter (org.foo.MySuperTest -> org/foo/my-super.feature)
- write your steps in the test class using cucumber API
- (optional) use injections in your test class (cdi, ejb, …)
Basically it can look like:
// imports skipped for readbility @RunWith(ArquillianCucumber.class) public class HelloCukeNewApiTest { @Deployment public static WebArchive war() { return ShrinkWrap.create(WebArchive.class, "cuke.war") .addClasses(HelloCuke.class) .addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml"); } @Inject private HelloCuke cuke; @When("^I have a cuke$") public void initCuke() { assertNotNull(cuke); } @Given("^I set cuke to \"([^\"]*)\"$") public void setCuke(final String name) { cuke.setCuke(name); } @Then("^I should have \"([^\"]*)\" in my cuke$") public void shouldHaveWhatWasSet(final String w) { assertEquals(w, cuke.getCuke()); } }
If your steps are reusable you can extract them in an external file and specify on the test class you want to use them simply with the @Glues annotation:
// imports skipped for readbility @Glues({ MySteps.class }) @RunWith(ArquillianCucumber.class) public class HelloCukeNewApiTest { // .... }
And the step class looks like:
public class HelloSteps { @Inject private HelloCuke cuke; @When("^I have a cuke$") public void initCuke() { assertNotNull(cuke); } @Given("^I set cuke to \"([^\"]*)\"$") public void setCuke(final String name) { cuke.setCuke(name); } @Then("^I should have \"([^\"]*)\" in my cuke$") public void shouldHaveWhatWasSet(final String w) { assertEquals(w, cuke.getCuke()); } }
Yes, the steps can get same enrichments as the main test class.
Note: it works with Drone but with current versions it needs at least a @Drone in the test class to be activated so you can add one even not used in the test class to workaround it (will probably be taken into account in next release of drone).
Same kind of annotation exists for features: to use multiple features in a single test simply decorate your test with @Features:
// imports skipped for readbility @Features({ "org/foo/my-other-steps.feature" }) @RunWith(ArquillianCucumber.class) public class HelloCukeNewApiTest { // .... }
Tested and approved with Apache TomEE and OpenEJB adaptors!
Nice stuff! Curious: why its own ArquillianCucumber runner as opposed to the standard Arquillian.class with a Cucumber extension or container?
simply to not rely on bytecode enhancement (+ @Test public void runCucumber() {}) which could not work in embedded mode. So cucumber is ran from the runner
if you have another idea i take it 😉