Java – Does it make sense to measure conditional coverage for Java 8 code

javajava8test-coverageunit testing

I'm wondering whether measuring conditional code coverage by current tools for Java are not obsolete since Java 8 came up. With Java 8's Optional and Stream we can often avoid code branches/loops, which makes it easy to get very high conditional coverage without testing all possible execution paths. Let's compare old Java code with Java 8 code :

Before Java 8:

public String getName(User user) {
    if (user != null) {
        if (user.getName() != null) {
            return user.getName();
        }
    }
    return "unknown";
}

There are 3 possible execution paths in the above method. In order to get 100% of conditional coverage we need to create 3 unit tests.

Java 8:

public String getName(User user) {
    return Optional.ofNullable(user)
                   .map(User::getName)
                   .orElse("unknown");
}

In this case, branches are hidden and we only need 1 test to get 100% coverage and it doesn't matter which case we will test. Though there are still the same 3 logical branches which should be covered I believe. I think that it makes conditional coverage statistics completely untrusted these days.

Does it make sense to measure conditional coverage for Java 8 code? Are there any other tools spotting undertested code?

Best Answer

Are there any tools that measure logical branches that can be created in Java 8?

I'm not aware of any. I tried running the code you have through JaCoCo (aka EclEmma) just to be sure, but it shows 0 branches in the Optional version. I don't know of any method of configuring it to say otherwise. If you configured it to also include JDK files, it would theoretically show branches in Optional, but I think it would be silly to start verifying JDK code. You just have to assume it's correct.

I think the core issue, though, is realizing that the additional branches you had prior to Java 8 were, in a sense, artificially created branches. That they no longer exist in Java 8 just means you now have the right tool for the job (in this case, Optional). In the pre-Java 8 code you had to write extra unit tests so that you could have confidence that each branch of code behaves in an acceptable way - and this becomes a bit more important in sections of code that aren't trivial like the User/getName example.

In the Java 8 code, you're instead placing your confidence in the JDK that the code works properly. As is, you should treat that Optional line just as code coverage tools treat it: 3 lines with 0 branches. That there are other lines and branches in the code below is something you just haven't paid attention to before, but has existed every time you've used something like an ArrayList or HashMap.

Related Topic