In the previous posts, we discussed two critical issues concerning testing the software.
First, we recognized the responsibilities of various teams regarding verifying the final product. We went through business, technical, and availability testing to understand how broad the topic is and how many parties should be involved.
Later, we learned the standard code features that, at least in theory, make the implementation eligible for testing. We described why core, ever-changing, and buggy code should make us consider writing tests. We should also remember to adjust our approach according to the project’s dynamic characteristics.
Today, we will talk about the complexity and granularity of different test approaches and how to choose between them.
Gradation of granularity
As we mentioned in the previous posts, the tests that are IT’s primary concern may be divided into three categories depending on their complexity and verification level.
The least powerful yet the easiest to create and run are unit tests. The rule of thumb is that it is usually a good idea if we can verify something using more straightforward tools. After we find any implementation critical enough to introduce some form of automatic validation, it is best to start by considering unit tests. Every use case is different, but conceptually starting automation from the lowest level and highest granularity will play out great. Sometimes, it is even better to write a couple of unit tests instead of designing a complicated higher-level alternative.
There are times when testing a single element is not enough, and we need to verify the link between independent modules. There, we are talking about integration tests. The proper gradation path says that we should only consider that kind of test when more granular ones — unit tests — are insufficient. Implementing integration scripts, we spend more time setting up the environment and executing the validation, yet we gain a unique ability to target potential problems between distinct parts of logic.
The last resort for automated testing is the utilization of high-level system tests. As we mentioned before, they are the most powerful but less precise, relatively expensive, and require a lot of time to complete. Due to end-to-end capabilities, they are often overused, and even though we can verify almost everything, we should not easily fall for that. We may create them, when we have first carefully contemplated the unit and integration alternatives. System testing exists solely to confirm multi-layer logic that other types of verification cannot evaluate.
The popular misconception is that we can create higher-level tests only when lower-level ones are already in place. That’s not the case. The rule states only that we should consider the lower level first.
There are many situations where only integration tests or even system ones are suitable. There is no need to force ourselves to come up with low-level verification just for the sake of imaginary testing order.
Another popular concept worth mentioning is the so-called “test pyramid”. It displays the relationship between different levels of validation. We have low-level unit tests at the bottom, where the pyramid is the widest. That makes us assume that we should have the highest number of those. Higher, we have integration scripts; thus, we should create them less often. Finally, at the very top, we have system tests. They are a high-level verification, and we implement them in the lowest quantity.
The test pyramid is real, but this is not why we should write more unit verification than the end-to-end alternative. This concept is merely a statistical effect of the pragmatic approach to writing code checks.
As mentioned before, we may start considering tests from the low-level verification. When we apply that approach across many use cases, it is natural that unit validation will appear in a greater number than any high-level solution. We should not confuse the cause with the effect.
We have different levels of software testing. As our default setting, we should try to verify the most we can with the least effort possible. This simple, pragmatic approach teaches us that when considering writing automated tests, we should start from the low-level validation. It is cheaper, so if it is enough, that’s probably better for us.
We should also remember that various general suggestions regarding testing are often the result of a particular approach to the topic. That’s why we should fully understand their cause before applying them to our project. Cheers!