Please note, as of August 2015, this article is superseded by the The Behaviour Specification Handbook
In my previous article, Behaviour Specification Writing Methodology - Part 1, I discussed the prerequisites for writing Behaviour Specifications / scenarios. This article elaborates on my tips and suggestions for the next stage - actually writing the Behaviour Specifications.
The Behaviour Specification Writing Meeting
After all the prerequisites have been satisfied (i.e. core business requirements are known and the initial, low-level technical design has been drafted), it is now time to write the Behaviour Specifications. Schedule a Behaviour Specification writing meeting!
The attendees of the Behaviour Specification writing meeting should include a holistic cross-section of the development team, including all the actual people who will be developing and testing the given functionality. I will come back to this point later.
The types of roles that should attend the meeting include:
- Technical Lead/Architect;
- Business Analysts;
- Test Analysts; and
Actual business representatives may of course also attend and can be especially useful if the requirements are not as clear as originally thought coming into this meeting. Assuming however that the requirements are crystal clear, the business representative would only attend predominantly for their own benefit and understanding, or for team building reasons.
Background Context and Requirements Overview
Please encourage the meeting attendees to ask questions at any time, and note all relevant feedback.
Start the Behaviour Specification writing meeting with some background context about the User Story. A walk-through of the business process leading into this User Story and other relevant high-level information about the business is always useful to set the scene.
It is also beneficial at this stage to now explain and walk the attendees through the requirements.
Technical Design Overview
Now have a technical representative walk the attendees through the low-level, draft technical design. Referencing some of the previously mentioned requirements, the technical representative should highlight the initially proposed systems and components and their relevant interactions.
This is a fantastic opportunity for the entire team (yes, even the Business Analysts) to understand the technical design and lingo, and initially challenge the technical design.
At this stage, let the attendees ask any more relevant questions and note all relevant feedback.
As necessary, evolve the technical design on the spot to cater for any issue that has been identified.
If there are significant issues with the requirements or technical design, then consider whether it is prudent to postpone the rest of this meeting.
What's Happening In Our Minds?
Throughout all of the above overviews and discussions, each attendee has now learned valuable implicit knowledge. This is the reason why the attendees should be the actual people who will do the development and testing - because throughout this meeting they are being transformed into the experts of this business functionality!
As the team next proceeds to write the behaviours of each component, multiple team members from different roles and perspectives are mentally testing each behaviour against their understanding of the solution - fantastically optimizing the feedback loop and enabling the team to avoid mistakes and reduce costly, wastful effort!
The process of writing the Behaviour Specifications is an important time where the attendees actively engage their mind and further collaborate and communicate. The result of the attendees actively engaging in the process is the growth of their own tacit knowledge and expertise. Again, this is the reason why the attendees should be the developers and testers of this functionality, because they become the experts who can most effectively and efficiently perform the implementation work.
To Gherkin or Not To Gherkin?
The Gherkin language is the most widely used and recognised business-readable domain-specific language (DSL) for specifying behaviours. Behaviours are defined within "Feature" files. Each Behaviour Specification is a "Scenario", which has a description, and then is further defined as executable steps, with each step beginning with word "Given", "When", "Then", "And" or "But". Depending on the platform, there are different tools for parsing and executing the Gherkin. For instance, there is Cucumber for Ruby, SpecFlow for .NET, jBehave for Java, Behat for PHP...
The new kid on the street is Gauge. In Gauge, behaviours are defined in "Specification" files that follow the Markdown syntax. Each Behaviour Specification has a heading, description and then is further defined as executable steps.
The main difference between the syntaxes used in Gauge and Gherkin is that the syntax used in Gauge is completely free and open. There is no "Given", "When", "Then" restriction like in Gherkin, and this flexibility can be a powerful draw card for some people.
However, with so much flexibility and power, there is the need for great responsibility and consistency - especially in an enterprise. In a medium or larger business or enterprise, consistency in language and style is important. If such a business were to use Gauge, the first thing the business should do, in my opinion, is to create a style guide to promote consistency between teams. And congratulations - now the syntax is restricted - and that flexibility is tamed.
In the end, we may as well have just used Gherkin. Sure, there are other cross-language features in Gauge that may pique your interest, but for my Behaviour Specification writing methodology, I am sticking with Gherkin. The recommendations presented here can apply to the Gauge syntax if you so desire.
Behaviour Specification Writing
Now that the requirements are understood by the team and there is general agreement that sufficient requirements are known and the draft technical design is sound enough, the process of writing the Behaviour Specifications can begin.
This behaviour writing process is best broken down into two phases - indeed, often it is worth working through these phases in different meetings, primarily to allow the attendees to have a rest in between:
- Identify and write all the Behaviour Specification descriptions; and
- Write the steps that would cause the desired behaviour to manifest.
All members of a software development team, including developers, analysts and stakeholders should be able to understand the Behaviour Specification descriptions and steps - because they should be written in commonly accepted business terminology. On a daily basis, the development team normally should be communicating with the rest of the business using accepted business terminology. Similarly the behaviours should be written in the same accepted business style of language (as much as possible). One result of this approach is the minimisation of the costs to train new staff.
This approach also promotes more consistent communication within the development and support teams - and even to the wider business itself. An example of communicating with a wider part of a business is a project team (the wider part) that engages an internal software development team. The project team certainly could be interested in the documented Behaviour Specifications of a system that the internal software development team authored. Whether other wider parts of a business would be interested is debatable, and I think it may only apply to businesses with quite a high degree of software development maturity.
As an overarching style guideline, I highly recommend that all wording used in a Behaviour Specification should only need to change if there is a change to the core business requirement - and specifically the wording should not need to be changed if there is a change to the implementation.
Finding the right words to use when writing a Behaviour Specification can be thought of sometimes as an "art" due to the delicate balance between not using language that is too technical or specific, and at the other end of the scale, using language that is too generic that the reader cannot grasp the essence or actual purpose of the behaviour. Finding this balance can be a challenge, especially for novices. The best advice I can give is to copy the style of existing behaviours that your team agrees are well-written.
Tip: Take samples of existing well-written Behaviour Specifications into each behaviour writing meeting and refer to them as necessary! It is often helpful to review these in the meeting to refresh everyone's memory.
Behaviour Identification and Descriptions
Take each system or component that is represented in the low-level technical design, one by one, and answer the following question:
"Within the context, boundary and responsibility of just that component, what are the behaviours that component should perform in order to fulfil all the requirements?"
Generally, each Behaviour Specification should be focussed individually on a single purpose or business rule. By doing this, each behaviour becomes a building block of tested functionality. When writing the next behaviour, you now have a "line of trust" that everything so far is working as specified, and you do not need to re-specify the behaviour or functionality of those building blocks.
End To End Behaviours
In addition to specifying the behaviours for an individual subsystem/component, you should also specify a small number of behaviours of end to end functionality (remember the Test Pyramid!). I suggest these end to end behaviours would be specified in their own feature file, separate from the feature file for the each component, since these behaviours span multiple subsystems/components.
Start With "Should"
Describe each behaviour specification / scenario in a sentence, beginning with the word "Should".
"Should" at the start of a sentence helps to focus both the author and reader clearly on the actual behaviour. Behaviours are described with verbs. The next word after "Should" is typically a verb... so this helps everyone reading the scenario description to quickly understand the scenario and how it may differ from others.
The behaviour specifications are both living, executable documentation as well as being classified as test assets. The behaviours also are the specification that developers should use when they write code. The only code that should be written by developers is code to satisfy a behaviour specification. No behaviour specification - no code. Importantly, behaviour specifications are NOT part of a formal, legal requirements document.
Each behaviour specification / scenario description is similar to a description of a system's capability. A system's capability is not described in terms of "it must/shall/will do XYZ" - that is how a "requirement" might be worded. Behaviour specifications are determined after the business requirements have been identified and agreed upon by stakeholders.
The scenario description is a specification of a system's expected behaviour - how the system should behave, based on all current knowledge and understanding. Dan North, the originator of BDD, in Introducing BDD eloquently describes more about the usage of the word "should":
"A more subtle aspect of the word should becomes apparent when compared with the more formal alternatives of will or shall. Should implicitly allows you to challenge the premise of the test: "Should it? Really?" This makes it easier to decide whether a test is failing due to a bug you have introduced or simply because your previous assumptions about the system's behaviour are now incorrect."
Use Present Tense
The scenario description makes more logical sense when written in the present tense, because it is the describing the most up-to-date, current, at the present time, expected behaviour.
Avoid Generic Verbs
Avoid the word "handle" or any other verb that is generic and hides the actual behaviour.
For instance, let us pretend that someone wrote the scenario description: "Should handle the situation when the total amount is not equal to the sum of all item amounts".
The above scenario description has both positive and negative points. On the positive side, the "when" part is descriptive and is an easily understandable, differentiating condition for the scenario. On the negative side however, "handle" is not actually describing the behaviour that occurs under in that situation. What is actually meant by "handle"?
A better alternative is to be more specific about the behaviour. For instance, "Should error when the total amount is not equal to the sum of all item amounts". Using "error" as a verb instead of "handle" clearly describes the actual type of behaviour that should be performed.
Positive and Negative Behaviours
All good test suites cover both positive / happy path and negative / sad path scenarios. Behaviour specifications are the same.
In my experience, prefixing the scenario description (even before "Should") with "Positive - " or "Negative - " allows someone reading the behaviour specification or test report to quickly and clearly determine whether the behaviour is focussed on the happy or sad path.
Primary / Business and Secondary / System Behaviours
It can be useful for the purpose of general understanding to distinguish between two different types of behaviours:
- Primary / Business Behaviours; and
- Secondary / System Behaviours.
A Primary / Business-based Behaviour is a behaviour that has been defined as a direct result of trying to fulfil a core business requirement.
A Secondary / System-based Behaviour alternatively is a lower-level behaviour needed by a system in order to enable or support the functionality of a Primary / Business Behaviour. A Secondary Behaviour is in no way less important than a Primary Behaviour - in fact, from one perspective, one can think that a Secondary Behaviour is more important because a specific Primary Behaviour is dependent upon and cannot function correctly without the Secondary Behaviour.
Examples of Secondary / System Behaviours include:
- Exception handling
- Transaction concerns
- Data storage and retrieval
- Performance concerns
- Auditing functionality
Unique Identifiers for Scenarios
When developers write new tests, modify existing tests and/or then need to run tests, it can be very useful to have a mechanism to easily identify and pick a specific scenario/test out of a list of many scenarios/tests. For instance, when developers are using their favourite IDE's Test Runner, if they want to find a specific scenario/test to run (even after using search or filtering on @tags), a unique identifier for each scenario can really help a human to visually find a specific scenario and select it more quickly.
I recommend including an incrementing number into each scenario description, with the number starting at one in each feature file.
In addition, prepending the feature name (or a shortened, unique version of it) helps to make a behaviour specification uniquely identifiable across multiple feature files.
Including all of the above information in each behaviour specification description makes life for all team members significantly easier when someone needs to reference a specific scenario in a communication, or navigate through a list of behaviours outside of the context of a feature file. For the small amount of discipline required, you will be cursing yourself and other team members if it isn't done and if you are the poor soul that now has to find a needle in a haystack. Just do it - it'll be worth it!
The template I find most useful for a scenario description is:
[FeatureName]-[Primary/Secondary]-01 - [Positive/Negative] - Should blah.
I acknowledge that at times this can become wordy, but in my experience the benefits of clarity with this approach have always trumped that small annoyance.
Zooming out from scenario descriptions within a feature file, let us now focus on other aspects related to the feature file.
File-System Folder Structure
I recommend grouping various feature files as appropriate into different file-system folders that follow a logical hierarchy. The top level of the hierarchy could be the name of an architectural capability or domain (a high-level grouping mechanism or category).
Subfolders could then be used for other logical groupings that make sense, and their names should include a verb (we are after all describing categories of behaviours). The subfolder / behaviour category name may describe the set of processes, actions, behaviour and activities that take place, and should be in business language - not implementation or system specific language.
Within the lowest-level subfolder are the feature files.
Below is an example folder structure:
Purchasing (top-level folder, also the name of a domain) | |---- ProcessingOrders (subfolder, a general category of behaviours) | |---- Shopping (subfolder, a general category of behaviours) |---- ManageShoppingCart.feature |---- CalculateShippingCosts.feature |---- ProcessPayments.feature |---- PlaceOrder.feature | |---- FulfillingOrders (subfolder, a general category of behaviours) |---- PickOrderItems.feature |---- ShipOrderItems.feature
The feature files for different subsystems typically will live in different code branches or projects within your source control repository. For consistency reasons, use the same folder structure for feature files across subsystems.
I also highly recommend not having whitespace in a folder or feature file name, as this can cause problems depending on the technology or development tools you are using.
At the top of a feature file is the feature name. I recommend making the folder hierarchy and grouping names part of the feature file's feature name value.
Each behaviour specification within a feature file is written from the context of a system, subsystem or component. Including the name of that subsystem or component in the description is also very using information, for the sake of clarity. Trickily, you may find that you have the exact same behaviour description and Gherkin in more than one component (for example, in both the User Interface and the back-end service layer), but the behaviour actually has a slightly different meaning in each because it must be understood and considered from within the context and perspective of that subsystem/component.
The template I find most useful for the name of a feature at the top of a feature file is:
Here is an example feature name, for a User Interface component:
And here is the same example feature, this time for the corresponding component in the back-end of a system:
In this example above, "Purchasing-ProcessingOrders-Shopping-ManageShoppingCart-ServiceLayer" is the "feature name" that you would include at the start of each behaviour specification description.
In my next article, I will discuss tips for writing the actual Given/When/Then steps of the Gherkin and about implementing the behaviours as automated tests.