2

I have a method that I am trying to unit-test. I cannot post the actual code, but it looks like this:

public int getTotal() throws MyException {
    int total = 0;
    try (ExternalResource externalResource = ExternalService.getResource()) {
        try (OtherExternal otherResource = externalResource.getOtherResource()) {
            if (someCondition) {
                total = otherResource.getTotal();
            }
        }
    }
}

JaCoCo is telling me that I am missing 4/8 branches on each of the try-with-resource blocks. I am testing that someCondition is true and someCondition is false, and JaCoCo shows that block completely covered.

I read this question, and I understand from the accepted answer that the issue is in how the byte code is generated.

I would like to be able to better understand how to identify the various branches that are generated, and then I can make a better judgement on wether to test them or not (are they unreachable, etc).

Community
  • 1
  • 1
Mark
  • 1,668
  • 2
  • 26
  • 53
  • 6
    Possible duplicate of [8 branches for try with resources - jacoco coverage possible?](http://stackoverflow.com/questions/17354150/8-branches-for-try-with-resources-jacoco-coverage-possible) – Antimony Dec 26 '16 at 17:58
  • I think that there are quite detailed analysis in answers on the question that you cite. If this is not enough, then could you please elaborate more about what is unclear? – Godin Dec 26 '16 at 20:45
  • I don’t get where “make a better judgement on whether to test them or not” is supposed to lead to. It’s impossible to test unreachable code, so there’s no need to “judge”. The testable scenarios should be understood without going into byte code details—every combination of completing the body with or without an exception and closing with or without exception. If testing these combinations doesn’t cover all paths, there’s nothing you can do to cover the remaining. Maybe using ECJ for testing helps, see also [try with resources introduce unreachable bytecode](http://stackoverflow.com/q/25615417) – Holger Jan 03 '17 at 13:16

2 Answers2

2

Per the change history in version 0.8.2:

Branches and instructions generated by javac 11 for try-with-resources statement are filtered out

I've tested this out locally using openjdk java8, and my try-with-resources now reports 100% branch coverage (even though the IOException is never thrown in my tests).

While it is good to test this behavior out, there are times when you can't easily reproduce such exceptions. For instance, in a method that just returns an open port:

public int getOpenPort() {
    try (ServerSocket boundSocket = new ServerSocket(0)) {
        return boundSocket.getLocalPort();
    }
}

I know of no simple way to force this code to throw IOException without adding a bunch of confusing and unnecessarily complicated code, just to pass a branch coverage check. Luckily, the new (v0.8.2) jacoco library gives this method 100% coverage with a single test just calling Assert.assertNotEquals(0, portChecker.getOpenPort());.

Shadow Man
  • 2,855
  • 1
  • 19
  • 33
-2

You have to test every Exception and every condition. But JaCoCo sometimes failed to identify correctly what is covered or not.

Erylis
  • 103
  • 1
  • 8
  • 1
    JaCoCo shows exactly what was executed on a bytecode-level. So I wouldn't name "failed" the fact that this doesn't look-well for you, when mapped back to source code in case of try-with-resource. – Godin Dec 26 '16 at 20:40