The goal is to verify each instruction of code.
A set of tests has to be built to check at least once the behaviour of every instruction. Four approaches are introduced in the article:
1. Statement Coverage Approach
The amount of checked code is called covered code. With reference to the total amount of code, you can describe the coverage as the ratio of covered code over total code. In real world cases, it’s usually pretty hard to reach 100% of coverage so usually a good level of coverage is considered around 90%.
Sometimes it can happen that after writing a complete set of tests, you spot an instruction that is never executed:
- Case #1: The instruction never executes because it’ss not covered by the whole tests set. In this case you should find a path that leads to the execution of such instruction, and build a test on top of that. Unfortunately this task is a non-deterministic problem, so it is not said that you can find the right path automatically: you may end up checking by hand going back through the instructions trying the various possible paths.
- Case #2: The instruction never executes because it’s in a “dead” part of the code, meaning there is no actual login flow that brings there. This situations are critical and must be inspected carefully.
2. Edge Coverage Approach
It checks that each logic branch of the code is covered.
For example if you have such a condition: “A and B”, you should test the behaviour of the code in case the condition gets true and in case it gets false. To do this actually, being an and condition, it would be enough testing when A is false (no matter B) and when A and B are true.
3. Condition Coverage Approach
It checks that each condition is covered.
For example if you have this condition: “A and B” , you have to create test cases where at least one time you have A = true, A = false, B = true, B = false.
Important Notice: the && and || are short-circuit operators, meaning they don’t evaluate the right hand side if it isn’t necessary. This fact cause sometimes to consider a variable as “not-evaluated” that for the purposes of testing does not cover true or false. It is a “wasted” case for the not-evaluated variable, but sometimes it is unavoidable.
4. Path Coverage Approach
The goal is to examinate all the possible path that can be followed during the code execution. In practice it is almost impossible to achieve. For example if you have a loop cycling 100 times that contains a call to a function that does not depend on the loop indexes and that can return in two different ways, you must test all the possible path that are 2 ^ 100 cases.