BDD encourages the description of the acceptance tests in a manner that is intelligible and transparent to the business users. This in particular may mean setting up explicitly via a series of scenario steps all the pre-requirements of a particular story or scenario. For complex scenarios this will rapidly lead to maintenance problems due to duplication of entire blocks of steps.
To help the user better manager more complex scenarios, JBehave allow the specification of entire stories as a pre-requisite for another story or scenario.
!-- A precondition to entire story GivenStories: path/to/precondition1.story Scenario: A scenario in which the user can run additional stories as pre-requisites !-- preconditions to scenario GivenStories: path/to/precondition2.story, ... path/to/preconditionN.story Given ... // normal scenario steps
When JBehave encounters the keyword GivenStories, it will run the (one or more) textual stories specified by path in the list (using the same Steps instances specified for the parent story) before proceeding to the execution of the scenarios (if at story level) or scenario steps (if at scenario level).
Another way to avoid duplication of textual scenario steps is to use the natural ordering of execution of the story classes. Typically, this means that the stories will be executed in the alphabetical order of their names and a convention can be adopted to have stories start with an alpha-numerical prefix, such as 'Snn' where 'nn' is an incremental number. This though has the disadvantage of having to run all stories leading up to the desired scenario, which in some cases can be unnecessary and time consuming. For example, for debugging purposes one may need to one run one scenario, which may have a dependency on just one other story. This is where GivenStories is most useful.
At times, it's useful only to depend on one or two scenarios of a story, and not the entire story. In this case, we can use an anchor in the story path to filter the scenarios that need to be executed. The scenarios will be filtered using meta parameters defined in the scenarios:
GivenStories: path/to/precondition.story#{id1:scenario1;id2:scenario2}
The precondition.story could e.g. contain three scenarios, of which we want to execute only the first two:
Scenario: Scenario 1 Meta: @id1 scenario1 Given ... // scenario executed as a precondition Scenario: Scenario 2 Meta: @id2 scenario2 Given ... // scenario executed as a precondition Scenario: Scenario 3 Meta: @id3 scenario3 Given ... // scenario not executed as a precondition
In the spirit of avoid unnecessary duplication, it useful at times to allow parametrization of given stories, i.e. executing them with different sets of parameters. Parametrized given stories work on the same principles of parametrized scenarios, using parameter injection. The only thing that differs with the case of parametrized scenarios is the convention by which the parameter sets are provided.
One way to parametrise the given stories is use the Meta: keyword:
Meta: @One uno @Two due GivenStories: path/to/precondition.story Scenario: A scenario which is executed after the parametrised story-level given stories Given ... // normal scenario steps
Another way is to use the Examples: keyword to collect the sets of parameters, allowing the user to provide via an anchor, an optional appendix of the form #{row} to the story path, which is interpreted as row number of the parameters to inject in the story execution.
For example, if we want to execute the same given story with two different sets of parameters, specified as the first and second row of the examples table:
Scenario: A scenario in which the user can run other stories as pre-requisites parametrized using the rows of the Examples table GivenStories: path/to/precondition.story#{0}, path/to/precondition.story#{1} Given ... // normal scenario steps Examples: |One|Two| |uno|due| |un|deux|
Conventionally, if the examples table is used to parametrized the GivenStories (i.e. if anchors are present in the story paths), it is assumed we are not using it to parameterize the scenario at the same time. This behaviour may be made configurable in the future, depending on the need.
Notes: The full path can be omitted if the GivenStories file is in the same directory as the story referring to it. The GivenStories file does not have to follow the naming conventions of the rest of the stories in your suite.