Composite Steps

BDD allows the scenario writer to vary the focus of the portion of the system under test, or the boundary of the system for the specific scenario. Some scenarios can be very detailed, zooming into the step-by-step process, others can be at a higher level, zooming out to give a bird's eye overview.

Allowing the composition of steps into groups whose execution can be triggered by the matching of a single step, called composite step, can be a very useful and powerful feature.

As usual, let's start with an example. Let's assume we've already defined a few steps.

Now we want to define a composite step that takes both parameters (customer and product) and executes the two "composed" steps with the parameter values provided, i.e. we want the composed steps to be executed when the following step is matched:

Given Mr Jones previously bought a ticket

where Mr Jones and ticket are parameter values for customer and product.

Annotation-based definition

We can define a new method and annotated as per usual, e.g. with the @Given annotation:

The novelty here is the introduction of the @Composite annotation. Composite steps are identified by this method-level annotation, which is independent of the @Given/@When/@Then annotations. The @Composite is optional and complements any of the @Given/@When/@Then annotations. Once the composite step is matched (via any of the supported mechanisms, e.g. parameter injection or parameterised scenarios), if the @Composite annotation is found on the matched method, the "composed" steps defined in the @Composite annotations are created using the parameters specified in the @Named annotations of the composite step. In other words, the composed steps are treated as a group of parametrised steps, much in the same way as the steps in a parametrised scenario.

Executing the composite step above is equivalent to executing:

Given Mr Jones previously bought a ticket
Given Mr Jones is logged in
Given Mr Jones has a cart
When a ticket is added to the cart

Note that the composite step is executed before the composed steps. The annotated method may of course be left to do nothing, as it's primary scope is to provide the compostion to other steps. It is also important to note that the composite step method needs to define named parameters (even if it uses matched parameters), as these are then used by the composed steps.

Textual-based definition

When a composite step does not require any implementation, it can be declared in a separate textual composite file:

Composite: Given $customer has previously bought a $product
Given <customer> is logged in
When a <product> is added to the cart

where

  • Composite: is a keyword;
  • Given $customer has previously bought a $product is a composite step pattern with parameters;
  • Given <customer> is logged in and When a <product> is added to the cart are composed steps

Composite files can contain multiple definitions:

Composite: Given composite step
Given composed step
And another composed step

Composite: Then composite step with parameter $param
Given composed step
When composed step using parameter <param>
Then one more composed step

Paths to composite files should be set in the configuration:

Also it's allowed to specify optional priority of the composite step:

Composite: Given prioritized composite step
Priority: 1
Given composed step
And another composed step

The default priority is 0