An introduction to Test-First Behavior-Driven Development, and acceptance testing with Gherkin, with some real-life Gherkin examples. Content created for C# code, but the principles do apply to other languages/environments.
3. “
”
BDD is a second-generation, outside-in, pull-based, multiple-
stakeholder, multiple-scale, high-automation, agile methodology. It
describes a cycle of interactions with well-defined outputs, resulting
in the delivery of working, tested software that matters.
Dan North at the 2009 Agile specifications, BDD and Testing eXchange
Ah, okay, now I understand it all.
11. How does a unit test look like?
• The AAA of unit tests:
• Setup
• Three stages:
• Arrange: do the necessary setup for the test, set prerequisites
• Act: do the actual testing
• Assert: verify the returned result
• Teardown
12. Unit Test Doubts
• When to test?
• Test First
• Test Last
• What to test?
• Separating units
• How to test?
• Inversion of Dependency, Dependency Injection, Mocking
13. Is Code Quality the Only Gain?
• Not with Test First TDD!
• You can use tests to specify how your code should work.
• Specification by Example:
“Specifications are supposed to be general, to cover all cases. Examples only
highlight a few points, you have to infer the generalizations yourself.”
• However – examples can be coded and validated easily.
14. An Example of Specification by Example
namespace RecentlyUsedList {
[TestFixture]
public class A_new_list {
[Test]
public void Is_empty() { … }
}
}
15. An Example of Specification by Example
namespace RecentlyUsedList {
[TestFixture]
public class An_empty_list {
[Test]
public void Retains_a_single_addition() { … }
[Test]
public void Retains_unique_additions_in_reverse_order() { … }
}
}
16. An Example of Specification by Example
namespace RecentlyUsedList {
[TestFixture]
public class A_non-empty_list {
[Test]
public void Is_unchanged_when_the_head_item_is_readded() { … }
[Test]
public void Moves_non-head_item_to_head_when_it_is_readded() { … }
}
}
17. An Example of Specification by Example
namespace RecentlyUsedList {
[TestFixture]
public class Any_list_rejects {
[Test]
public void Addition_of_null_items() { … }
[Test]
public void Indexing_past_its_end() { … }
[Test]
public void Negative_indexing() { … }
}
}
18. Test First Style
• Simple rules:
1. A non-compiling unit test is considered a failed unit test.
2. Never write production code without having a failing test that necessitates writing that
code.
3. Never write more production code than what is minimally required to fix your failing
test.
4. When a unit test fails, you don’t commit anything to the system until the failing unit
test is passing again.
20. Test First Cycle
1. Add a new unit test
2. Run all unit tests to see the test fail
3. Write your code
1. Write a small segment of the test code
2. Run all unit tests to see the test fail
3. Write production code to have your test pass
4. Run all tests to see them all pass
5. Refactor your production code
6. Run all tests to seem the all pass
22. Continuous Running of Unit Tests
• Visual Studio Enterprise: Live Unit testing
• NCrunch
• (Severe performance impact)
23. So, we are writing Test First Code
• Our coverage is at about 100%
• There is nothing else to test
• Everything works perfectly
• And we have arrived to the promised land of good quality code.
26. Unit testing is for devs
• Software is a holistic system – the whole is more than the sum of the
components.
• The fact that some parts work perfectly in separation does not mean that
they work perfectly together as well.
• Unit testing only guarantees code quality improvements, but might not
provide benefits solution-wise.
• The whole process cannot be tested as the business / the customer / the
product owner are not involved.
30. Higher level testing problems
• System level functions are difficult to define
• Software Requirements Specification:
• A lengthy document
• Suitable for a waterfall model – but not a good fit for an agile model
31. But we have already solved this issue…
• With User Stories. Right? Well… sort of.
• How does a User Story look like?
• As a [user type]
• I want to [task to perform]
• In order to / so that I [benefit/value]
32. User Story Example
• User story:
• As an Administrator
I want to be able to create User Accounts
in order to grant users access to the system.
• Yeah, seems simple enough…
33. Acceptance Criteria Example
1. If I am an Administrator, I can create User Accounts.
2. I can create a User Account by entering the following information about the User:
a. Name,
b. Email address,
c. Phone Number
d. License Number (Power/Basic/None),
e. Account Status (Active/Inactive),
f. Reports to (from a list of “Active” Users)
3. I cannot assign a new User to report to an “Inactive” User
4. I cannot assign a new User to report to a User if it creates a cyclical relationship (e.g., User 1 reports to User 2 who reports to User 1)
5. The system notifies me that it sent an email to the new User’s email address, containing a system-generated initial password and instructions
for the person to log in and change their password.
6. I am able to verify with the intended recipient of the email that it was received.
38. Language Imperfections
• “A common risk with software development includes
communication breakdowns between Developers and
Business Stakeholders.”
• Text and/or speech is sometimes incapable of conveying
clear, undisputable meaning.
• Or at least it is really difficult to achieve it.
• Acceptance criteria as plain text usually falls short.
This is not a test pyramid
39. “
”
The only way to rectify our reasonings is to make them as
tangible as those of the Mathematicians, so that we can find
our error at a glance, and when there are disputes among
persons, we can simply say: ‘Let us calculate, without further ado, to
see who is right.’
Wilhelm Leibniz: The Art of Discovery (1685)
See also:
John Wilkins: An Essay towards a Real Character and Philosophical Language (1668)
Umberto Eco: The Search for a Perfect Language (1995)
40. What can a developer implement?
• Specification by Example
• Remember the AAA of unit testing? We’d need something similar.
41. “
”
“A ubiquitous language is a (semi-)formal language that is shared by all
members of a software development team — both software developers and
non-technical personnel.
[…]
The language in question is both used and developed by all team members as
a common means of discussing the domain of the software in question.”
Eric Evans: Domain-Driven Design: Tackling Complexity in the Heart of Software
Ubiquitous Language
43. DDD
Okay, then, what is DDD?
“an approach to software development for complex needs by connecting the
implementation to an evolving model”
Okay, then, what is a “domain”?
It is “application domain”, a “domain of discourse”, a “problem sphere”, or a “universe”. It is the
sphere of knowledge on the problem that our software is aiming to solve.
Great. What is this model you speak of?
A system of abstractions (a set of entities and business rules) that describes selected
aspects of a domain and can be used to solve problems related to that domain.
44. So, let’s borrow this concept from DDD…
… and use it in TDD for higher level tests!
46. GWT is AAA
• Arrange ~= Given
• Act ~= When
• Assert ~= Then
Given that I have Arranged the system for the test
When I perform the tested Action
Then I can Assert the conditions that pass the test
48. How are Acceptance Tests different from Unit
Tests?
• They test the same things
• Only less granularly: they hide implementation details that programmers (and Unit
Tests) should be concerned with, but business (and Acceptance Tests) should not.
• Acceptance Tests is a subset of Unit Tests (remember the test pyramid?)
49. AAA for the Business
• Specification in plain English for the business people
• Specification that can be implemented for the developer
50. Gherkin Specification
Feature: Calculator
As a math idiot
I want to be told the sum of two numbers
in order to avoid silly mistakes
Scenario: Add two numbers
Given I have entered 50 into the calculator
And I have pressed the “Add” button
And I have entered 70 into the calculator
When I press the “Equals” button
Then I should see the result “120” on the screen
52. Language for Developers
public class CalculatorTestSteps
{
[Given(@”I have entered (.*) into the calculator”)]
public void GivenIHaveEnteredIntoTheCalculator(int v)
{
// …
}
// …
}
53. How does this resolve linguistic ambiguity?
• It creates a common language between People Who Know What The
Software Should Do (PO, BA, tester)and the People Who Know How To
Write The Software (developer).
54. Okay, but what is the magic behind it all?
• The power of mathematics™!
• As Gherkin specifications are actually nothing, but…
55. Finite-State Machines
• We have a set of States, and a set of Actions (State Transitions)
• We start from a State, and performing an Action we arrive to another State
• A simple example is…
56. … a coin-operated turnstile
• We have two states:
• Open
• Locked
• We have two actions:
• Insert coin
• Push arm
57. State transitions
• We start the system in the “Locked” state
• Inserting a coin:
• In the “Locked” state moves the system to the “Open” state
• In the “Open” state leaves the system in the “Open” state
• Pushing the arm:
• In the “Locked” state keeps the system in the “Locked” state
• In the “Open” state moves the system to the “Locked” state
58. So how is a Gherkin a FSM?
Given I have entered 50 into the calculator
And I have pressed the “Add” button
And I have entered 70 into the calculator
When I press the “Equals” button
Then I should see the result “120” on the screen
Given I am in state S1
When I receive event E1
Then I transition to state S2
59. Back to Resolving Linguistic Ambiguity
• Acceptance criteria is written in Acceptance Test form, using Gherkin.
• My implementation task is complete when my Acceptance Tests are green.
• The PO should write the “happy path” (positive test cases), the tester should
write the “unhappy paths” (negative test cases) – usually together with the
developer.
• This is ATDD – Acceptance-Test-Driven Development.
63. “
”
I’m glad that you’ve asked that question…
A List of Most Common Lies of the World, entry #3:
64. “
”
BDD is a second-generation, outside-in, pull-based, multiple-
stakeholder, multiple-scale, high-automation, agile methodology. It
describes a cycle of interactions with well-defined outputs, resulting
in the delivery of working, tested software that matters.
Dan North at the 2009 Agile specifications, BDD and Testing eXchange
Ah, okay, now I really understand it all.
67. Let me rephrase it…
“behavior-driven development is a software development process that […]
combines the general techniques and principles of test-driven development
with ideas from domain-driven design and object-oriented analysis and
design to provide software development and management teams with
shared tools and a shared process to collaborate on software development.”
68. So basically…
• BDD = Agile + TDD + ATDD?
• Sort of.
• What else?
• High automation (CI, CD, auto-testing).
• Tooling (C#: SpecFlow by TechTalk)
69. Okay, does it then tell me when to run my
Acceptance Tests?
• Of course it does!
• It tells you to run them when you run your Unit Tests
• That is, any time you build
• On the CI machine
• Or locally.
70. Okay, but I really want to understand that
quote…
Well, if you insist…
71. “
”
BDD is a second-generation, outside-in, pull-based, multiple-
stakeholder, multiple-scale, high-automation, agile methodology. It
describes a cycle of interactions with well-defined outputs, resulting
in the delivery of working, tested software that matters.
Dan North at the 2009 Agile specifications, BDD and Testing eXchange
• Second-generation: Has more in common with Lean and Kanban than with XP and Scrum
• Outside-in: focuses on satisfying the needs of stakeholders
• Pull-based: tasks are not allocated by the management, stories are created on-demand
• Multiple-stakeholder, multiple-scale: yeah, makes sense
• High automation: CI, CD, running tests automatically, tests act as acceptance criteria
72. How should I imagine developing in BDD?
• Well, it’s basically ATDD, so you use the ATDD cycle.
• Let me see a demo!
75. Feature: Accessing user management
As a maintenance user
I want to be able to access user management in standalone mode
so that I can grant or revoke access to specific parts of the system.
Background:
Given the following "offline" users exist
| UserName | Description | UserLevel |
| Olivia | An operator user | Operator |
| Sophie | A supervisor user | Supervisor |
| Mia | A maintenance user | Security |
And I am logged out
And the "Header Panel" is visible
76. Scenario: User management menu item appears for an administrator user
When I log in as "Mia"
Then the "User Management Menu Item" is visible
Scenario: User management is not visible when no user is logged in
Then the "User Management Menu Item" is not visible
Scenario: User management menu item doesn't appear for supervisor user
When I log in as "Sophie"
Then the "User Management Menu Item" is not visible
Scenario: User management menu item doesn't appear for operator user
When I log in as "Olivia"
Then the "User Management Menu Item" is not visible
77. Scenario: Clicking on the User Management menu item opens the User Management dialog
When I log in as "Mia"
And I click the "User Management Menu Item"
Then the "User Management Dialog" opens
Scenario: Pressing the Exit button closes the User management dialog
When I log in as "Mia"
And I click the "User Management Menu Item"
And I click the "Exit Button"
Then the "User Management Dialog" closes
And the "Main Menu Screen" is displayed
78. Feature: Adding a new user
As a maintenance user
I want to be able to add new users
so that I can grant access to specific parts of the system.
Background:
Given the following "offline" users exist
| UserName | Description | UserLevel |
| Olivia | An operator user | Operator |
| Sophie | A supervisor user | Supervisor |
| Mia | A maintenance user | Security |
And I am logged in as "Mia"
And the "User Management Dialog" is displayed
And the following users are displayed
| UserName | Description | UserLevel |
| Olivia | An operator user | Operator |
| Sophie | A supervisor user | Supervisor |
| Mia | A maintenance user | Security |
And no user is selected
79. Scenario: Pressing the Add New User button opens the Add New User dialog
When I click the "Add New User Button"
Then the "Add New User Dialog" is displayed
Scenario: Attempting to create a new user with an empty UserName
shows an error message
When I click the "Add New User Button"
And I enter the following user data
| UserName | Description | UserLevel |
| | A new operator user | Operator |
And I confirm the "Add New User Dialog"
Then an "Error Dialog" is displayed
And the displayed error message is "User name must not be empty!"
80. Scenario: Adding a new user creates a new user in the system
When I click the "Add New User Button"
And I enter the following user data
| UserName | Description | UserLevel |
| Oliver | A new operator user | Operator |
And I confirm the "Add New User Dialog"
Then the "Add New User Dialog" closes
And the "User Management Dialog" is displayed
And the following users are displayed
| UserName | Description | UserLevel |
| Oliver | A new operator user | Operator |
| Olivia | An operator user | Operator |
| Sophie | A supervisor user | Supervisor |
| Mia | A maintenance user | Security |
81. Scenario: Canceling the addition of a new user does not modify the user list
When I click the "Add New User Button"
And I enter the following user data
| UserName | Description | UserLevel |
| Oliver | A new operator user | Operator |
And I cancel the "Add New User Dialog"
Then the "Add New User Dialog" closes
And the "User Management Dialog" is displayed
And the following users are displayed
| UserName | Description | UserLevel |
| Olivia | An operator user | Operator |
| Sophie | A supervisor user | Supervisor |
| Mia | A maintenance user | Security |
82. Feature: Deleting an existing user
As a maintenance user
I want to be able to delete existing users
so that I can revoke their access to the system.
Background:
Given the following "offline" users exist
| UserName | Description | UserLevel |
| Olivia | An operator user | Operator |
| Sophie | A supervisor user | Supervisor |
| Mia | A maintenance user | Security |
And I am logged in as "Mia"
And the "User Management Dialog" is displayed
And the following users are displayed
| UserName | Description | UserLevel |
| Olivia | An operator user | Operator |
| Sophie | A supervisor user | Supervisor |
| Mia | A maintenance user | Security |
And "Sophie" is selected
83. Scenario: Deleting an existing user removes the selected user
When I click the "Delete User Button"
And I confirm the "Confirm User Deletion Dialog"
Then the following users are displayed
| UserName | Description | UserLevel |
| Olivia | An operator user | Operator |
| Mia | A maintenance user | Security |
Scenario: Canceling the deletion of an existing user does not modify the user list
When I click the "Delete User Button"
And I cancel the "Confirm User Deletion Dialog"
Then the following users are displayed
| UserName | Description | UserLevel |
| Olivia | An operator user | Operator |
| Sophie | A supervisor user | Supervisor |
| Mia | A maintenance user | Security |
84. Feature: User management dialog buttons
As a maintenance user
I want my selection on the user list to influence the buttons I can press
so that I can see at a glance what are the available actions with the
current selection.
Background:
Given the following "offline" users exist
| UserName | Description | UserLevel |
| Olivia | An operator user | Operator |
| Sophie | A supervisor user | Supervisor |
| Mia | A maintenance user | Security |
And I am logged in as "Mia"
And the "User Management Dialog" is displayed
And the following users are displayed
| UserName | Description | UserLevel |
| Olivia | An operator user | Operator |
| Sophie | A supervisor user | Supervisor |
| Mia | A maintenance user | Security |
85. Scenario: User management list button statuses are correct when no user is selected
When I clear the user selection
Then the "Add New User Button" is enabled
And the "Exit Button" is enabled
But the "Edit User Button" is disabled
And the "Delete User Button" is disabled
Scenario: User management list button statuses are correct when a user is selected
When I select "Sophie"
Then the "Add New User Button" is disabled
But the "Exit Button" is enabled
And the "Edit User Button" is enabled
And the "Delete User Button" is enabled
86. Feature: User listing
As a maintenance user
I want to be able to see a list of users that can access my system
so that I can see or edit their data.
Background:
Given the following "offline" users exist
| UserName | Description | UserLevel |
| Olivia | An operator user | Operator |
| Sophie | A supervisor user | Supervisor |
| Mia | A maintenance user | Security |
And I am logged in as "Mia"
And the "Header Panel" is visible
87. Scenario: User management shows list of standalone users
When I click the "User Management menu item"
Then the "User Management Dialog" is displayed
And the following users are displayed
| UserName | Description | UserLevel |
| Olivia | An operator user | Operator |
| Sophie | A supervisor user | Supervisor |
| Mia | A maintenance user | Security |
Scenario: No user is selected on the User Management Dialog when it initially opens
When I click the "User Management menu item"
Then the "User Management Dialog" is displayed
And no user is selected
88. Feature: Editing an existing user
As a maintenance user
I want to be able to edit existing users
so that I can modify their details.
Background:
Given the following "standalone" users exist
| UserName | Description | UserLevel |
| Olivia | An operator user | Operator |
| Sophie | A supervisor user | Supervisor |
| Mia | A maintenance user | Security |
And I am logged in as "Mia"
And the "User Management Dialog" is displayed
And the following users are displayed
| UserName | Description | UserLevel |
| Olivia | An operator user | Operator |
| Sophie | A supervisor user | Supervisor |
| Mia | A maintenance user | Security |
And "Sophie" is selected
89. Scenario: Pressing the Edit User button opens the Edit User dialog
When I click the "Edit User Button"
Then the "Edit User Dialog" is displayed
And the following user data is displayed
| UserName | Description | UserLevel |
| Sophie | A supervisor user | Supervisor |
90. Scenario: Editing user data of an existing user modifies the selected user
When I click the "Edit User Button"
And I modify the "User Name" field to "Sophia"
And I modify the "Description" field to "An ex-supervisor user"
And I modify the "User Level" field to "Operator"
And I confirm the "Edit User Dialog"
Then the "Edit User Dialog" closes
And the "User Management Dialog" is displayed
And the following users are displayed
| UserName | Description | UserLevel |
| Olivia | An operator user | Operator |
| Sophia | An ex-supervisor user | Operator |
| Mia | A maintenance user | Security |
91. Scenario: Canceling editing of an existing user does not modify the user list
When I click the "Edit User Button"
And I modify the "User Name" field to "Sophia"
And I modify the "Description" field to "An ex-supervisor user"
And I modify the "User Level" field to "Operator"
And I cancel the "Edit User Dialog"
Then the "Edit User Dialog" closes
And the "User Management Dialog" is displayed
And the following users are displayed
| UserName | Description | UserLevel |
| Olivia | An operator user | Operator |
| Sophie | A supervisor user | Supervisor |
| Mia | A maintenance user | Security |