Background
I am trying to help my team organize for a new mobile app project. We have chosen to follow BDD (see also BDD definition) in order to capture plain English requirements that form a contract between stakeholders and developers for each individual user story.
We use the acceptance tests to document each user story's requirements. Acceptance tests are written before sprint planning. Developers refine and add to the tests during sprint planning.
We define Acceptance Criteria as a list of rules (eg: input validation, default values, etc) and Acceptance Tests as a list of Cucumber scenarios. We plan on using Calabash for mobile testing.
I feel acceptance criteria/tests are a more agile and therefore better solution to more formal requirements documents.
I feel I have found an effective solution fo, but I would like to understand how others are collecting requirements and writing acceptance tests.
Problem
There is a debate in the Cucumber community of imperative vs declarative test steps. I lean toward imperative, because a developer must know what a deliverable user story looks like.
I do not feel UI coupling aka brittle tests is an issue. There are ways to decouple the UI from the test (eg: page objects). I also do not feel that having detailed steps make it hard for a non-technical stakeholder to understand (unless they don't know how to use a web browser or mobile device, but that's a separate issue).
I may be misappropriating the term "Acceptance Test". In my use, an acceptance test is not on the same level of scope as a unit test. I view an acceptance test as a high level integration test.
The Example
- As a guest
- I want to login
- to access app functionality
Imperative Test
- Scenario: Valid login
- Given I am on the "login" screen
- When I enter "email@domain.com" in "email"
- And I enter "password1" in "password"
- And I tap "login"
- Then I see "login successful"
Declarative Test
- Scenario: Valid login
- Given I have a valid account
- Then I can login
These both can cover the same functionality and the latter is shorter, but it does not say if I can login with a username, email or facebook/twitter/google/etc account. It's just not enough to actually code a solution
The Question
How do you capture the requirements for a feature with declarative steps?
Nicely written question!
The requirements for a feature are recorded in the step definitions.
Hence in your imperative example:
this could be made declarative by re-writing it as:
The steps to navigate to a valid account (i.e. implementing the acceptance criteria which defines what "valid" means) can then be implemented in the step definition for this scenario statement. The same will apply for the opposite scenario i.e.
Again, the steps to implement this scenario which satisfy the acceptance criteria can be implemented in the underlying step definition.
Taking this declarative approach means that you lose the (imperative) requirements from the feature (i.e. what exact steps need to be performed), making it harder for the business to see exactly what these scenarios are doing from just reading the feature file. However, what you gain is that the tests become less brittle, as the specific steps to achieve a task are recorded in the step definition, and this step definition can be shared amongst many features.
At my company we wrestle with the same concerns, and we find that in some cases it's better to use imperative rather than declarative, and vice versa. For example, in your case the steps which make up "Given I have a valid account" may be used in many features, so making it declarative is rational. However if you have a feature where many different string values are inputted, then in that case it's probably best to write them imperatively.
"Horses for courses!"
It'll be very interesting to see other answers to this question from the SO community.
I recently visited a shop/online to buy a Washing machine and a Dish washer. All I wanted was to buy one that uses less water and has a quick wash. But the details I encountered were overwhelming; such as RPM, Thickness of inner drum, Total connected load in KW etc.
Imperative style may appear suitable from your simple example above but in reality it makes reading scenarios harder and boring. You can experience it by reading 10 scenarios from a project in which you are not directly involved at a technical / day-to-day level.
Given that one of the objective of using cucumber is to bring in transparency across the project, in particular the non-technical users, declarative style is much better at getting management actively involved. I have seen that in my projects.
Here is a fictitious story. Try and implement it in imperative style, come back and read it in couple of days, you will realize that its too boring.
Another link that you may wish to read How to implement UI testing without shooting yourself in the foot