This time, we’re looking into one of the most common pain points with Given-When-Then: writing automated tests that interact with a user interface. People new to behaviour driven development often misunderstand what kind of behaviour the specifications should describe, and they write detailed user interactions in Given-When-Then scenarios. This leads to feature files that are very easy to write, but almost impossible to understand and maintain.
Here’s a typical example:
Scenario: Signed-in users get larger capacity Given a user opens https://www.example.com using Chrome And the user clicks on "Upload Files" And the page reloads And the user clicks on "Spreadsheet Formats" Then the buttons "XLS" and "XLSX" show And the user clicks on "XLSX" And the user selects "500kb-sheet.xlsx" Then the upload completes And the table "Uploaded Files" contains a cell with "500kb-sheet.xlsx" And the user clicks on "XLSX" And the user selects "1mb-sheet.xlsx" Then the upload fails And the table "Uploaded Files" does not contain a cell with "1mb-sheet.xlsx" And the user clicks on "Login" And the user enters "testuser123" into the "username" field And the user enters "$Pass123" into the "password" field And the user clicks on "Sign in" And the page reloads Then the table "Uploaded Files" contains a cell with "500kb-sheet.xlsx" And the table "Uploaded Files" does not contain a cell with "1mb-sheet.xlsx" And the user clicks on "spreadsheet formats" Then the buttons "XLS" and "XLSX" show And the user clicks on "XLSX" And the user selects "1mb-sheet.xlsx" Then the upload completes And the table "Uploaded Files" contains a cell with "1mb-sheet.xlsx" And the table "Uploaded Files" contains a cell with "500kb-sheet.xlsx"
A common way to avoid such issues is to rewrite the specification to avoid the user interface completely. We’ve looked into that option several times in this article series. However, that solution only applies if the risk we’re testing is not in the user interface, but somewhere below. To make this challenge more interesting, let’s say that we actually want to include the user interface in the test, since the risk is in the UI interactions.
Last week, you voted on options for fixing a broken user-interface interaction test.
We’re very glad to have a guest expert this time. Andy Knight, blogging as Automation Panda, took the challenge on and provided a comprehensive answer on his blog.
The community had some great ideas as well this week. Here are some of the best responses.
Gaspar Nagy proposed something similar, particularly looking at the causes of the risks that the tests are supposed to be protecting against:
I definitely would dig deeper into that risk. The risk is in the UI integrations, but in what nature?
A: Is it that fragileness of the UI interaction solution causes our users to not be able to get the business value (e.g. they cannot register, because of a js glitch). In this case I would use (some) business-language scenarios and automate them through the UI (or to the UI as well). But other non-BDD tests, like UI smoke tests or approval tests would work also fine.
B: If the risk is if we understood the UI interaction properly and whether our solution solves the right expectation (E.g. the validation of the new user name happens instantly even before submitting the registration form.), then UI interaction terms can sneak into the scenario. But even in this case I would try to focus on the UI concepts, not the individual HTML elements, so I would say “When I provide my user name as ‘foobar’” instead of “When I type ‘foobar’ into the text box ‘tbUserName’”.
Christian Quirós proposed “You re-write the specification layer (feature file) to avoid implementation details and to describe the system behavior instead, then, you have multiple implementations of the automation layer.” He suggested applying Hexagonal Architecture, a pattern to isolate the business domain and provide abstractions for interactions, where a feature file can be “driving the application through the UI by using another step definition implementation”. This is an excellent approach for situations when we want to hide UI details from the specification but still execute tests through the UI. Christian also proposed applying the Screen Play pattern to restructure the user interactions in terms of required behaviours.