So, we're going to start off with the Python statement "if A or B and C:",
so let's make sure to nail down the precedents so we don't have to remember that.
If A is true, or else both B and C are true,
then we're going to execute some code.
And so now let's look what it takes to get full MC/DC coverage
of this bit of code.
The first thing we can see is that we're going to need to test each of the variables
with both to their true and false values,
because the conditions, that is to say, the conditions are A, B, and C here,
need to take on all possible values.
We can see that each of the conditions is going to need to be assigned both the true value
and the false value during the test that we run.
Now, the other part of MC/DC coverage--that is, does every condition independently affect
the outcome of a decision--is going to be a little harder to deal with.
Let's take a look.
Let's first consider the input where A is true, B is false, and C is true.
We don't even need to look at the B and C part of the expression,
because we know that if A is true, then the entire condition succeeds.
This maps to a true value.
What we want to verify here is that we can come up with a test case where every condition
independently affects that outcome of a decision.
Since our top-level operator here is an or,
let's see how we can make the whole thing come out false.
While the B and C clause already came out to false,
because if B is false, then the whole thing comes out to false.
If we make A false, then the entire decision will come out to be false,
and if we've changed only A and we haven't changed B and C,
then we've shown that A independently affects the outcome.
So, let's write another test case.
Our second test case with A being input as false, B input as false, and C as true,
leads the overall decision to come out as false.
We've shown now that A independently affects the outcome.
So let's try to do the same thing for B and C.
If we want to continue trying to leave everything the same and only change the value of one variable
in order to establish this independence condition,
let's this time try flipping the value of B.
We're going to have A being false, B being true, and C being true.
If we look at the overall value of the decision, what now happens is that B and C evaluates to true,
so it doesn't matter that A evaluates to false.
Overall, decision evaluates to true this time.
By flipping the value of only B we've satisfied this condition for the input B.
That is to say we've shown that B independently affects the outcome,
because when we change B, the overall value of the decision went from false to true.
Now let's see if we can do the same thing for C.
We're going to leave A and B the same, and we're going to pass in C as false.
Now let's look what happens.
B and C evaluates to false, and then also A is false, so the entire value of the boolean decision
comes out to be false.
By only changing C and by seeing that the overall decision changes value,
we've now shown that C independently affects the outcome of the decision.
So, what I believe we have here is a minimal--of if not minimal, at least fairly small--
set of test cases that together gets 100% MC/DC coverage
for this particular conditional statement in Python.
You can see here that this isn't a particularly complicated conditional.
We could've written one much more complicated,
and if we had, we probably would've had a fairly hard time reasoning this stuff out by hand,
and what we would've needed to do in that case is probably draw out a full truth table.
So, let's look at the idea behind MC/DC coverage.
Why would this be a good thing at all?
What it's done is taken a statement that was really very easy to cover
using either branch coverage or statement coverage.
That is to say it's pretty easy to take this and make it either come out to be true or false overall
on the force testing of the individual components of the boolean logic.
Basically, the idea is that when we have complicated boolean expressions,
they're truth tables become rather large.
What that means is there's a lot of complexity hiding in those truth tables.
When there's complexity, there are probably things we don't understand,
and that means they're probably bugs.
It turns out that the domain of interest for MC/DC coverage--
that is to say embedded control systems that happen to be embedded in avionics systems
end up having generally lots of complicated conditionals.
It's definitely desirable when people's lives depend on the correctness
of these complicated conditional expressions to force people to test them rather thoroughly.
The other idea behind MC/DC coverage is that as part of establishing
that every condition independently affects the outcome of a decision
we're going to figure out when we have conditionals
that don't independently affect the outcome of a decision.
If you think about it, why would you have a conditional involved in a conditional expression
which doesn't affect the outcome.
What that basically means is there's a programming mistake, and it may be a harmless mistake.
That is to say, the extra conditional being part of a decision
may not affect the correctness of the overall system,
but what it means is somebody didn't understand what was going on,
and probably there's something that we need to look at more closely
and probably even change.
Another thing you can see, looking at MC/DC coverage,
is that getting it on a very large piece of software is going to take an enormous amount of work.
This is why it's a specialized coverage metric for the avionics industry
where the critical parts of the codes end up being fairly small.
That's MC/DC coverage, and we're not going to take a programming quiz on that,
since first of all, as you saw, it gets to be a pain pretty quickly,
and second we lack good tool support for MC/DC coverage in Python.