Automated tests is something very common in our days, but only write automated tests isn't enough if you want to stand out in the job market, during this article, we will see some definitions that can help us write high-quality automated tests.
Summary
- Why write high-quality automated tests
- Overview of SOLID Principles
- Characteristics for high-quality automated tests
- Conclusion
Why write high-quality automated tests
Before study a topic or try to understand any definition, we need first ask ourselves why we should spend time writing high-quality automated tests? Create automated tests is already an task that get a lot of our time and now we need to think in make them with quality?
I like to think that the effort from today it's a gift for my future self.
We know that automated tests are wonderful to help the development team during the project, a lot of problems are avoid due the automations but, what make a lot of automations become a little monster is the maintenance and keep it updated due the changes of the project, based on it, we already have a good reason to think in the quality of our automated tests.
We will see a lot of concepts during this article that can help us improve the quality of our automated tests.
Overview of SOLID Principles
First, let's do a quick overview about SOLID principles. SOLID is a mnemonic acronym for five design principles, the goal of this principles is to help us writing more understandable, flexible and maintainable software:
- SRP - Single Responsibility Principle: Every Software module should have only one reason to change
- OCP - Open/Closed Principle: Software entities(classes, modules, functions, etc) should be open for extension but closed for modification
- LSP - Liskov Substitution Principle: You should be able to use any derived class instead of a parent class and have it behaved in the same manner without modification
- ISP - Interface Segregation Principle: Clients should not be forced to implement interfaces they don't use. Instead of one fat interface, many small interfaces are preferred based on groups of methods, each one serving one sub-module
- DIP - Dependency Inversion Principle: High-level classes should not depend on low-level classes. Both types should be created based on abstractions. These abstractions shouldn't depend on any low-level details. All details should use the abstractions instead
We won't go more deep on this concepts because this isn't the focus of this article and knowing the definition of each one, we will be able to understand the characteristics that will be mentioned later.
If you want to go deep and understand better the SOLID principles, you can check it in this articles:
Era SOLID o que me faltava - PT BR
The S.O.L.I.D Principles in Pictures
Characteristics for high-quality automated tests
Now that we know the SOLID principles, we can start to look on the characteristics that our automated tests should have to achieve a high-quality, and they are:
- Test Independency
- Test Maintainability and Reusability
- Readability
- API Usability
- Extensibility
- Learning Curve
- KISS
Test Independency
The principle states that each test should be completely independent and self-sufficient. Any dependency on other tests or third-party services that cannot be controlled should be avoided at all costs. We get access to many benefits if we integrate the principle in the development of our automated test:
- Resilience - developing our tests in a non-dependent way makes them more resilient if some other test or 3rd party services fail to setup/delete the required data or leave the system in a state that is not expected.
- Faster test development - speed-up the long-term maintenance and test development since we don’t need to make a long analyzation session wondering what will happen if we change/delete this test.
- Random run order - allows us to be able to run the tests in random order and in different subsets.
- Parallel testing - connected to the previous point, not only we can run the tests in random order, but we can run them in parallel, which cannot happen in the case where the tests should be run in a particular order, because they depend on each other to set up required data.
Test Maintainability and Reusability
We can say that Maintainability and Reusability are a couple in the world of automated tests. We don't have maintainability without reusability.
Reusability is related to DRY(Don't Repeat Yourself) principle where the most basic idea is to reduce long-term maintenance cost by removing all unnecessary duplication. There's different ways and techniques that can be used to improve the reusability of your tests. The Page objects model and the SOLID principles are examples that can help you to have your tests more reusable(OCP principle, DIP principle) and with this, your maintainability will be improved was well.
When you have a good reusability, where you are able to extend or reuse what you already have created in your automation, the better the maintainability is, will be easier for you and your team support the existent code, accommodate new requirements or just fix some bugs.
Readability
Is related to how easy your test is to read. If you look at a method in your code and you are not able to response the question: "What does this method do?" , then your method most probably has more than one purpose, therefore it doesn't follow the Single Responsibility principle.
So, when creating your methods, variables, think in meaningful names, avoid abbreviations.
API Usability
The API is the specification of what you can do with a software library. API usability means how easy it is for you as a user to find out what the methods do and figure out how to use them. If we are talking about a test library - how much time is needed for a new user to create a new test? It is related to the learning curve. In the programming community, we sometimes use another term for the same thing called syntactic sugar. It describes how easy it is to use or read some expressions. It sweetens the programming languages for humans. The programming statements become more concise and clearer.
Extensibility
"Did you write your tests in a way that if you add this new functionality, you would not affect your existing tests?"
When creating automated tests and thinking in the Usability and Maintainability we can create share libraries that can be used by multiple teams, so we should pay attention to how one change will affect what already exists.
Learning Curve
"How easy is it for someone to learn by himself?"
The learning curve is tightly connected to API usability, but it means something a bit different. If a new member joins your team, is he able to learn by himself how to use your test automation framework or he needs to read the documentation if it exists? Or you have a mentoring program where you need to teach these new members yourself every time how to use your code?
KISS
"Keep It Simple Stupid". The below quote from Martin Fowler best describes the principle.
“Any fool can write code that a computer can understand. Good programmers write code that humans can understand.”
This principle is the criteria that will define if your automated test have high-quality or not. When you have the previous ones implemented, your code became simple and easy to learn.
Conclusion
This article was an introduction of some characteristics that we should consider to have a high-quality automated tests. The main goal to use this is to have an code that is easy to maintain, read and learn with all the benefits that automation can bring to our daily lives. If you want to go more deep in this, I recommend the book Design Patterns for High-Quality Automated Tests from Anton Angelov, which this article was based on.
I hope this content will be useful for you.
If you have any questions, feel free to reach out to me!
Top comments (4)
Really nice topic around good written tests, I'm always trying to think about this specially now that i'm working with legacy codebases and big refactors.
On the topic of mocks for test quality, what are your opinions ? at what point the test uses too much mock and stop being useful or good?
I like mock data when you are validating only the design or when you need to test only the front-end part, like the flows and things like this. You can use them for component tests, they'll be more fast than doing all the integration. But you can adjust for your scenario.
If possible, please provide code examples of
high
vslow
quality of tests. Thank you.Hi I'm preparing a pratical tutorial implementing this concepts.