Say I am developing a Shopping cart, BDD, with Cucumber. A cart is rather complex and has many bells-and whistles, but this could be just as well for "a blog" or "a user profile".
I've always considered the "cart" to be the Feature and the bells-and-whistles to be the Scenario's. However, this can make large Feature files and goes against the literal meaning of a Scenario. Here is how that would look:
Feature: Cart
So that I can buy items
As a user
I want to place items in a cart
#.... Many more scenarios
Scenario: Empty a filled cart
Given 2 products in my cart
When I visit the cart page
And I press "Empty cart"
Then I should see the text:
"""
Your cart is empty.
"""
Scenario: Empty an empty cart
Given 0 products in my cart
When I visit the cart page
Then I should not see the "Empty cart" button
# Many more Scenario's
The more details are filled out, the longer this "empty cart" group becomes. I wonder, should "emptying cart" be considered a standalone Feature? This would lead to many Features, all containing but a few Scenario's. The Scenario's then become more like "contexts". Like so:
Feature: Emptying Cart
So that I can reconsider my shopping-spree
As a user
I want to empty my cart
Scenario: with a filled cart
Given 2 products in my cart
When I visit the cart page
And I press "Empty cart"
Then I should see the text:
"""
Your cart is empty.
"""
Scenario: with an empty cart
Given 0 products in my cart
When I visit the cart page
Then I should not see the "Empty cart" button
What is a good guideline for making something a Feature? When should I regroup Scenario's into their own Feature? How many Scenario's does a Feature commonly have?
You can shorten your scenarios - and even get rid of a few - by phrasing them in declarative, rather than imperative, language.
For instance:
Given the cart has two products in
When I empty the cart
Then I should see it has nothing in it.
This could be just as true of an actual shopping cart as a UI. It has no implementation details in it. You can see that some of the steps correspond to more than one of yours; this is a good thing as it keeps the complexity in the code where it's more maintainable.
If we phrase your other scenario this way, we get:
Given my cart is empty
Then I should not be able to empty it again.
There's no "when" here because the "then" is simply true for that state.
Do you really need this scenario, though? Would it kill you or your company to release with the ability to empty an already-empty cart? This is essentially aesthetic. It's been added to make the UI easier to use, and the only way to tell if a UI is usable is to actually use it. If you ever find these kind of scenarios, I recommend taking them out. You can always unit-test the logic that leads to the button being enabled or disabled.
If you change to this style of language, then remove any scenarios that are only testing aesthetics and usability, you'll find your feature files become much, much smaller.
I also recommend putting the most interesting or surprising scenarios at the top. For instance, this would be a more interesting scenario (and yes, it has two "whens" in it, because it describes the behavior associated with an interaction between two different users):
Given a user put a copy of "Moby Dick" in his cart
When the last copy of "Moby Dick" is sold
And the user comes back to look at his cart
Then it should tell him, "Sorry, this item is currently out of stock."
This would be even more interesting:
Given a user put a new copy of "Moby Dick" in his cart
And there are second-hand copies of "Moby Dick" available
When the last new copy of "Moby Dick" is sold
And the user comes back to look at his cart
Then it should tell him, "Sorry, this item is currently out of stock."
And it should also show the way to the second-hand copies with,
"2nd hand copies are available."
That would be a differentiating scenario; something that your shop did differently to other shops, and therefore of great interest to the business.
By putting the most interesting ones at the top, it won't matter that the feature file is long. We all know how a cart works for buying and selling items, and we're not reading the scenarios at the bottom by that stage anyway.
Andy Waite is right when he says there are no hard rules, so play it by ear; if it doesn't work, do something differently. Hopefully these hints will help too.
You can group features into folders e.g. you might have a folder cart
and then feature files for emtpy_cart.feature
, update_cart.feature
, etc.
There's no hard rules, but personally I wouldn't put more than about 8 scenarios in a single feature file.
Check out Relish's own docs for a great example of how to structure features: https://www.relishapp.com/relish/relish
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With