They say that the cardinal rule of BDD is:
One Scenario, One Behavior!
This is great, but the fact is that I got a single action that will trigger many different things in the system.. and I must verify all of them will happen. Here is my Gherkin:
Scenario: Buying a single product to be delivered now
Given I am in the checkout page
When I checkout the order
Then the order should be created to the specified address
And the order should be set in pending state
And ops must be notified via a slack notification
And A shopper must be auto assigned the order via a push notification
And A retailer must be notified about the order via a push notification
And A transaction must be recorded in the payment gateway
And My wallet should be deducted by the payment amount
This seems real ugly. But now I'm not sure how to separate it. Doing a Background doesn't seem to cut it since in a background, you are only setting up the groundwork for multiple scenarios where each scenario will have it's when and then pair (In my case I'm using Behat, which has a given, when and then in each scenario after a background).
Advice?
The most straightforward way of tackling this, is by following the advice you quoted in your question:
One Scenario, One Behavior!
To implement this advice, simply split the bloated scenario up in multiple smaller ones.
For instance:
Scenario: Buying a single product to be delivered now
Given I am in the checkout page
When I checkout the order
Then the order should be created to the specified address
And the order should be set in pending state
Scenario: Notifying ops of the purchase
Given I am in the checkout page
When I checkout the order
Then ops must be notified via a slack notification
...etc.
Many of the given
's in your scenario aren't very much related to each other. They have some temporal relationship, because they all happen to happen right after an order was placed, but that's all.
You could even go a step further and consider grouping them as different features.
After all, notifying ops is a different feature from processing payments, which in turn is different form stock calculations.
In addition to the answer by @Stratadox (split scenarios by behaviour) - Given
step should never refer to the user interface or a stage in the user journey. The page the user is on is irrelevant to the business logic.
The Given
step (like the Arrange
step in unit testing) is used for setting the system up in a given state. This state set up in the Given
step determines the outcome (the Then
step)
For example:
"the order should be created to the specified address" - this outcome might have occurred as a consequence of the customer entering their address correctly (and in this case it might be necessary to specify actual the address so that it can be asserted in the Then
step).
"My wallet should be deducted by the payment amount" - in order to assert that the system is in the correct state after charging your wallet, we'd probably check some kind of data persistence and we'd also check for a specific amount. What amount? Its the amount you specify in the Given
step that is directly related to the outcome of this scenario
Scenario: Being charged the correct amount on successful purchase of product
Given I have £10 in my wallet
When I purchase a Toaster Oven for £4
Then I should have £6 left in my wallet
"A shopper must be auto assigned the order via a push notification" - this is an outcome that can be asserted as part of a "successful purchase" check. The only thing it depends on is whether the purchase was successful or not. And you can bundle together the assertions like "shopper notified, retailer notified transaction recorded" - and give them one name, one line in your scenario e.g.:
Given Jon has the following items in his basket:
| Macbook Pro | £3000 |
When Jon checks out his basket
Then a purchase of "xyz" for £3000 by Jon should have gone through
The last step here will imply doing three assertions under the hood. Which is fine as everyone know what's implied by a "purchase going through"