Typically, in addition to testing code during its writing process, developers are also responsible for unit testing. Tests that verify low-level modules, methods, functions, and procedures usually require a deep dive into the code context, and if these tests are not written during or immediately after development, the complexity and effort required to write such tests increase significantly. This is because even after several days, the developer will need to immerse themselves in the code again, and someone who did not write the code will also need to study it to understand how to test it.
Therefore, I conclude that developers should be the ones to write unit tests. And if these tests are not written immediately, it's better not to write them at all and focus on testing at a higher level. In my opinion, this approach would be much more effective in this situation.
Next, the Quality Assurance (QA) team comes into play. Their work differs significantly from the tests written by developers. They test the high-level interaction of modules, the functionality (business logic) of the application, and user interaction but do not engage in low-level code testing for the reasons I outlined above. This team includes both manual testers and people involved in test automation. Who exactly is responsible for integrating into CI pipelines is an organizational question. In our case, let's assume it's a DevOps engineer responsible for the entire test automation pipeline.
The manual testing team studies the documentation and functionality of our software product and writes step-by-step scenarios for properly testing the system. These scenarios are then used for both manual testing and automation.
Part of the team responsible for automation creates tests, which I also divide into two parts:
- Developer tests
- System tests
Please note, that the term "system test" here has a slightly different meaning than is commonly understood in testing theory.
Developer tests are tests that work in an isolated part of the application. Technically, they are the same as unit tests, created according to the same rules and using the same frameworks, but they test not low-level module code but higher-level interaction within the application (integration tests) and, if possible, the correctness of the system's core functionality (functional tests). Essentially, in the code, one can emulate a specific user request and check how the system responds to it. Just without using the UI. These tests, like unit tests, can be run without deploying a full installation of the system. They are usually very fast and do not require special resources to execute.
System tests are any tests that require a full deployment of the system instance. These include API tests, UI tests, load tests, and others. They usually use special frameworks and require more time to execute. Consequently, the "cost" of running such tests is higher.
In the end, we get two categories of tests:
- fast and "cheap" but more superficial and synthetic
- slow and "expensive" but deeper and more comprehensive
Following the
Pareto principle, we can expect that fast tests will help us detect about 80% of bugs, while slow tests will help find the remaining ones.
And based on this logic, to significantly improve the quality of our software, it's enough to run fast tests, for example, with each pull request, while running slow tests less frequently and on special occasions (for example, when preparing for releases).
And as a result, we get the following scheme