30

Is there a simple way to tell which branch I am missing? I.e. I have some code like this:

if (x || y) {
    // do stuff
}

In the coverage highlighting there is a yellow dot in Eclipse that says:

1 of 4 branches missed

but I would like to know which branch is missing.

Line
  • 1,529
  • 3
  • 18
  • 42
tor
  • 636
  • 3
  • 7
  • 18

7 Answers7

19

There is a quite easy workaround - just put each logic predicate on a separate line, like this:

if (x 
    || y) {
    System.out.println("BRANCH: " + x + ", " + y);
    // Do stuff
}

Now when you run the analysis, the marker should point directly to the branch that is missed. After you've added coverage, you can reformat your code the right way.

SusanW
  • 1,550
  • 1
  • 12
  • 22
Bolesław Denk
  • 553
  • 7
  • 15
  • Brilliant! By the way, if Eclipse "format on save" keeps putting these back on one line, just edit the file in a text editor instead. – Noumenon Jan 09 '20 at 15:19
18

What can x and y be?

  • true || true is true (Not covered because of JVM optimization: if the first condition is true, the second won't be evaluated due to short circuit evaluation)
  • false || true is true
  • true || false is true
  • false || false is false
user_
  • 104
  • 1
  • 1
  • 11
Maroun
  • 94,125
  • 30
  • 188
  • 241
  • 1
    The question is, how do I know which of these branches were not followed? I know for sure it is not the false/false case, since the "else" case is executed in some cases. – tor Mar 19 '13 at 08:07
  • 7
    Shouldn't it be the true || true case that isn't covered? – Jason Dec 30 '13 at 16:03
  • I just stumbled back on this question - had to go back to remembering old digital-logic truth tables and "don't care" conditions. – Dave G Jan 07 '16 at 23:17
  • 1
    I think the point of this question is that sometimes you have complicated conditions like foo != null && foo.equals("bar"). Or I've had cases where I had to unit test ridiculous legacy control statements that are difficult to keep track of. – Salsero69 Oct 25 '17 at 15:57
  • 2
    The "Not covered because of JVM optimization" statement isn't quite right. It's not an optimization: it is in the language specification for the `||` operator, that the second operand must not be evaluated if the first evaluates to true. It is a hard functional requirement, not an optimization, and defined in the Java language, not the JVM. – SusanW Nov 27 '20 at 23:05
  • 2
    And ... actually, given that it mustn't evaluate the second operand when the first is `true`, how does it distinguish `true || true` and `true || false`? I don't see how `y=true` and `y=false` are distinguishable! I'm thinking that there are only 3 cases: `true`, `false||true`, and `false||false` - what do you think? This smells like a mistake in the coverage tool...! – SusanW Nov 27 '20 at 23:41
  • @SusanW Good point. Thanks for your comment. – Maroun Nov 29 '20 at 06:40
13

An open issue on the github repo for Eclemma's parent, jacoco, suggests that such a feature would actually be a bit difficult to include.

However, even without an Eclemma feature, if the goal is just to figure out the branches missed in a specific case, you could instrument your code to keep track. The simplest example is old fashioned print statements:

if (x || y) {
    System.out.println("BRANCH: " + x + ", " + y);
    // Do stuff
}

Then look at the output and see what branches you actually hit (e.g. java ... | grep "BRANCH:" | sort | uniq). (not terribly satisfying, I know.)

teichert
  • 3,963
  • 1
  • 31
  • 37
  • I have the same error on lines like `return expr1 && expr2`; where I have unit tests that exects returned value to be true. So it must have visited both expressions. :/ – juanmf Aug 20 '18 at 05:07
6

The answer is true|| true was not covered.

This is because once the JVM has found the first condition to be true, then it won't run the second condition (it's optimized) which means that portion of the code is never run.

As Maroun said, 3 out of 4 branches will allow the conditional to pass. If you're still worried about code coverage, you can refactor the conditional to be a && instead of a ||.

(x || y) is the same as (!(!x && !y)) and this will allow you to test all conditions since there are only three branches now.

The original form of the conditional is often seen in guard statements:

if (obj == null || obj.hasError())
{
    throw new RuntimeException();
}

This will never allow you to check if obj is null AND has an error because it will throw a Null Pointer Exception.

If code coverage is important, then just use this form:

if (!(obj != null && !obj.hasError()))
{
    throw new RuntimeException();
}
Jean-François Savard
  • 20,626
  • 7
  • 49
  • 76
Brett Pyke
  • 180
  • 1
  • 3
  • 1
    or perhaps can use eager operator `|` or `&` unless you intentionally short-circuit the operations, in which case you can never get full branch coverage. – tkokasih Aug 15 '14 at 09:25
  • 1
    @BrettPyke how come there are three branches in case of '&&' ? – ishan3243 Feb 06 '15 at 08:41
  • 9
    @BrettPyke if you transform (x || y) to !(!x && !y), you have the same shortcut problem of converage with the expression !(false && false). – Leonid Glanz Dec 16 '15 at 11:54
  • @LeonidGlanz Exactly. If there's a bug in the coverage tool, that it mis-evaluates OR conditions but not ANDs, then that's one thing. But doing an inversion of the logic doesn't change the fact that there are 4 cases and only 3 of them are reachable. – SusanW Nov 27 '20 at 23:20
0

There are likely implicit branches either from nested statements within the if block or statements from expanding your x or y predicates.

Read this: http://emma.sourceforge.net/faq.html#q.fractional.examples

Tim Bender
  • 20,112
  • 2
  • 49
  • 58
  • Yes, I figured. There are 4 different possible combinations of the x and y boolean values, and I'm guessing only three of them were ever observed. The question is, how can I tell which case did not happen? Or equivalently, which cases were observed? – tor Mar 19 '13 at 08:11
  • "1 of 4 branches covered" indicates that 3 branches are not covered. I think it should be obvious (from coverage highlighting inside the block) which code paths are not covered. – Tim Bender Mar 19 '13 at 17:40
  • 1
    Sorry, my mistake completely! The message actually says "1 of 4 branches missed." I'll update immediately... – tor Mar 20 '13 at 03:30
0

What will be the result of below expressions ?

  • true || true is true
  • true || false is true
  • false || true is true
  • false || false is false

If you notice in 1st and 2nd case when you have 1st parameter as TRUE, you don't need to check 2nd parameter.

  • true && true is true
  • true && false is false
  • false && true is false
  • false && false is false

Or if you see scenarios with AND operator, if first parameter is FALSE you never need to check for 2nd parameter.

And hence you are never able to check 1 branch out of 4 branches.

  • 1
    So - does this mean the coverage tool is warning about not testing branches which are completely unreachable? That sounds like a bug. – SusanW Nov 27 '20 at 23:15
-1

To get full coverage, avoiding the implicit choices of the compiler, you'd have to rewrite the if statement into two as

if (x) {
    // do stuff
} else if (y) {
    // do the same stuff
}

This will get full coverage but will be correctly flagged as redundant code. I'd rather live with the yellow line once I see the issue than add this messy structure to the code.

Michael McKay
  • 650
  • 4
  • 11