Chapter 3.3.1: Decoupling from the UI
Individual steps of a good test tell a story. If we get it right, domain experts and programmers understand the story equally well.
Disclaimer: You are reading an early version of the text! The final version of the book will be revised and may contain additional content.
A good test answers the question of what, not how.
Ideally, a test contains all information about circumstances and the particular results we expect under those circumstances. The test is the link between the problem domain and the program code. Individual steps of a good test tell a story: the story of a user solving a problem or performing a specific task using our software. If we get it right, domain experts and programmers understand the story equally well.
When we run our tests, we want to know if our application satisfies the requirements of the problem domain and achieves the previously specified desirable outcomes. Implementation details of a feature do not help us understand a particular aspect of the problem domain; therefore, we should avoid polluting our tests with them if possible. All information about implementation details, i.e., how we implemented a feature in the code, should therefore be hidden.
We've already looked at how to decouple our tests from implementation details of specific modules of our code (e.g., Vue Components) above. However, by decoupling the tests from the user interface we go one step further: a really good test hides not only information about details of the code but also about how our users interact with the application. So we want to consistently apply the principle of information hiding not only to individual modules but also to the user interface of our application.
This may sound a bit abstract at first. So let's imagine that a user has to click on a particular button in our application to add a product to a shopping cart. In this scenario, the information about the user having to click a button hints at UI specifics. Of course, a button is one of many ways to implement this functionality. However, it is equally conceivable that a voice command could replace the click on the button. So we are interested in keeping the knowledge of how precisely a specific feature works, i.e., how a user, step by step, interacts with our application out of our tests.
The anatomy of a typical test
Let's take a look at a concrete example: If we want to check whether the expected number of items is in a shopping cart after adding two products, we can write the following test for this purpose: