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.
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.
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
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