As I understand it based on this Given When Then wiki page, Given
steps interact with the app to set the precondition state, When
steps interact with the app to attempt to set the desired new state being tested, and Then
statements read the state of the app without modifying it.
Is reusing When
steps as Given
steps for subsequent states a good idea?
For instance, in a simple shopping cart application, I might write:
Given the user is interested in some item
When the user adds the item to their cart
Then the cart will include the item
Given the user adds the item to their cart
When the user checks out
Then the user will see a summary of their purchase including the item
Given the user checks out
When the user cancels an item
Then the item should be canceled
And the user should be refunded
There is a similar question here reusing the user's previous interaction in a wizard, but it seems to disagree with Uncle Bob's finite-state-machine interpretation in that the answer suggests making the steps much less rigorous, while Uncle Bob implies that the steps ought to be rigorous enough to make an intelligible state transition diagram out of them. I completely accept the advice to remove all the user-interface jargon from them and focus only on business terms, but there does seem to be a difference between logically connecting business terms as I have tried to do here, and just making logically unconnectable steps that are only connected by "unseen" glue code.
You're correct in that Gherkin scenarios describe steps that Arrange, Act, and Assert within the application under test.
Uncle Bob's finite state machine can be described in Gherkin, if you have enough Gherkin statements. It's important to remember, though, that each scenario in Gherkin starts from the initial state, not from the state at the end of the scenario located above it in a feature file.
To rephrase, each scenario MUST stand on its own.
The potential duplication of test steps is of less importance than describing a complete scenario. One reason is that test runners may selectively run scenarios, which would cause test failures if the precursor scenario was not executed. Other test runners may run scenarios in parallel, which would also play havoc if such dependencies were allowed.
It's perfectly acceptable, and common practice, to have a Given step repeated in several scenarios.
Your example would be more properly stated something like:
Given the user is interested in some item
When the user adds the item to their cart
Then the cart will include the item
Given the user has added an item to their cart
When the user checks out
Then the user will see a summary of their purchase including the item
Given the user purchases an item
When the user cancels the item
Then the item should be canceled
The third Given statement could include steps in its definition to have the user put the item in the cart and check out, although it could also simply create an invoice from scratch. That's the beauty of Gherkin: it doesn't matter how the precondition is implemented, the verification is that the action causes the expected outcome.