Consider the following C++ code, where x, y, and z are Integers :
if ( (A==1 || B==20) && C==30 ) {
cout << "Decision is True!";
}
else {
cout << "Decision is False!";
}.
We want to write a group of test cases T to test that the above Boolean expression: ( (A==1 || B==20) && C==30 ) is written correctly without inspecting the code with eyes. This task is very useful, especially when the Boolean expression is complicated. One example for a test case can be: If A, B, and C are at some moment are equal to 1, 20, and 30 respectively, the code within the first if condition should execute ("Decision is True!" to be printed) in case that the coder didn't commit a writing mistake within the Boolean expression. In simpler format :
A=1, B=20, C=30 -> "Decision is True!".
The modified condition/decision coverage (MC/DC) is a code coverage criterion to achieve that testing. It allows generating test cases that can discover if :
- there is any missing condition that should be present,
- there is any wrongly implemented "OR" or "AND" operation(s),
- or there is any wrongly inverted condition.
Firstly, let's define two concepts: Condition and Decision. We mean with Condition the atomic (indivisible, it's also called leaf-level) conditions. (A==1 || B==20) is a condition, but it's not atomic, while (A==1) is an atomic condition. On the other hand, Decision is the whole big condition under testing. It's ( (A==1 || B==20) && C==30 ) in our example code.
------------------------------------------------------------------------
For Condition Coverage:
(A==1), (B==20), and (C==30) are conditions. If the test cases in T guarantee that each condition is true in some test case and is false in another test case, we achieve condition coverage.
(A==1), (B==20), and (C==30) are conditions. If the test cases in T guarantee that each condition is true in some test case and is false in another test case, we achieve condition coverage.
Example for a T that achieve condition coverage:
T = {
A=1, B=20, C=30 -> "Decision is True!" ,
A=0, B=0 , C=0 -> "Decision is False!" }
------------------------------------------------------------------------
For Decision Coverage:
If the test cases guarantee that the Decision is true in some test case and is false in another test case, we achieve decision coverage. So, the above example T achieve decision coverage too.
------------------------------------------------------------------------
For Modified Condition/Decision Coverage:
For each atomic condition X, there should be two test cases T1 and T2 in T that achieve the following three conditions:
- In T1 X is true, while it's false in T2.
- In T1, the Decision is true, while it's false in T2.
Or the opposite. - T1 and T2 are common for all the conditions other than X.
For example:
T = {
A=0, B=0 , C=30 -> "Decision is False!" ,
A=0, B=20, C=30 -> "Decision is True!" ,A=0, B=20, C=0 -> "Decision is False!" ,
A=1, B=0 , C=30 -> "Decision is True!" }
In the previous example test cases, for the condition (A=0),
(A=0, B=0 , C=30 -> "Decision is False!") is T1, and
(A=1, B=0 , C=30 -> "Decision is True!") , is T2. Note that, for any Boolean expression there will be at least n+1 test cases to achieve Modified Condition/Decision Coverage, where n is the number of conditions.