Question

I was wondering if it was possible to get path coverage(executing all paths) but not condition coverage? Also, how about the other way, condition coverage, but not path coverage? A concrete example would help. I know that path coverage does not imply condition coverage because you can execute all paths without making at least one condition false, for example.

Was it helpful?

Solution

That depends to some extent on how you choose to interpret those two terms, but the answer is probably that both are possible.


First off, most reasonable definitions of the two terms make it very easy to get path and branch coverage without condition coverage. For example:

function isPositive(x) {
    return x > 0;
}

Testing isPositive with only one value of x will get you path and branch coverage but not condition coverage.


Similarly, it's also very easy to get condition and branch coverage while failing to get path coverage.

function printPositivities(x, y) {
    if(x > 0) {
        std::cout << "x is positive";
    } else {
        std::cout << "x is non-positive";
    }
    if(y > 0) {
        std::cout << "y is positive";
    } else {
        std::cout << "y is non-positive";
    }
}

If you test this once with positive numbers, then again with non-positive numbers, you will achieve condition coverage (both if conditions turn out true and false) and branch coverage (since all four std::cout statements get executed) but not path coverage (since you miss the paths where one is positive and the other isn't).


The more interesting question (which you didn't ask, but for some reason I thought you did) is whether you can get condition coverage without branch coverage.

To do that you need a reason for the program to branch that does not qualify as a "condition". In many languages, the x in if(x) doesn't have to be a boolean, but in most cases that is probably more of an uninteresting loophole than a genuine answer since x will still have to be "truthy" or "falsy". The most interesting non-loophole cases of "non-boolean branching" that I can come up with are:

1) catch blocks. In most (all?) languages with exceptions, a catch block never gets executed unless an exception actually gets thrown, so it's easy to write code with perfect condition coverage that never throws any exceptions, and then add a try/catch block even though there's nothing there to catch.

2) Go's select syntax on channels:

select {
case msg1 := <-channel1:
    fmt.Println("received", msg1)
case msg2 := <-channel2:
    fmt.Println("received", msg2)
}

This causes the program to wait until either channel1 or channel2 has data that can be received, then it receives that data and executes the block of code corresponding to the channel that it received from. Note that this actually blocks execution for an arbitrary length of time, rather than calling channel1.isReady() or something, which is why I believe this counts. If you simply ensure that channel1 always has data to receive and channel2 doesn't, you have a branch coverage failure.

OTHER TIPS

It depends on your description of conditions.

If you are accepting logical expressions such as

  'logical(x) OR logical(y)' 

as two seperate conditions and your language is lazy evaluating expressions then by only one value you can cover the path, but not the condition on

  'logical(y)'
Licensed under: CC-BY-SA with attribution
scroll top