简体   繁体   中英

How to ignore @SneakyThrows of Lombok in Jacoco code coverage?

I use JaCOCO to see code coverage (and use the Intellij plugin for it). I have @SneakyThrows of lombok on my code. Since @SneakyThrows does nothing but converting a checked exception to a unchecked exception, I hope it does not affect the code coverage.

However, it seems that it drops the code coverage:

I have tried to add lombok.addLombokGeneratedAnnotation = true to my lombok.config , but no use.

Thanks for any suggestions!

You can't ignore a certain code path, jacoco has no support for that (neither it can ignore a method). Its unit of measure, for a lack of better term, is a .class file. Since jacoco looks at the .class file, that is generated after lombok processor kicks in, for it - you simply have path that is un-tested.

In simpler words, jacoco sees your file like it never had lombok annotations. So you can't "exclude" an annotation. I feel your pain - we have modules where people have enforced a very high number of coverage, and these catch blocks are un-tested, almost all the time.

Adding @Generated with lombok.addLombokGeneratedAnnotation = true will only work for Lombok annotations that generate whole methods. However, @SneakyThrows will only add a try-catch block around the code inside of the annotated method.

For example if you have following method and want to sneaky-throw the InterruptedException from Thread::sleep :

package com.example;

import lombok.SneakyThrows;

public class Example {

  @SneakyThrows
  public void someMethod() {
    System.out.println("This method does a few things");
    System.out.println("Like counting to 10");
    for (int i = 0; i < 10; i++) {
      System.out.println(i);
    }
    System.out.println("And waiting a second");
    Thread.sleep(1000);
  }
}

The generated code would look like this:

package com.example;

public class Example {

  public void someMethod() {
    try {
      System.out.println("This method does a few things");
      System.out.println("Like counting to 10");

      for (int i = 0; i < 10; ++i) {
        System.out.println(i);
      }

      System.out.println("And waiting a second");
      Thread.sleep(1000L);
    } catch (Throwable e) {
      throw e;
    }
  }
}

You actually only want to ignore the try-catch in the coverage check, not the whole method, so if Lombok added @Generated to the whole method you will ignore more coverage than intended.

What you could do, is extracting the code that throws a checked exception to a new method and add both @Generated and @SneakyThrows .

package com.example;

import lombok.Generated;
import lombok.SneakyThrows;

public class Example {

  public void someMethod() {
    System.out.println("This method does a few things");
    System.out.println("Like counting to 10");
    for (int i = 0; i < 10; i++) {
      System.out.println(i);
    }
    System.out.println("And waiting a second");
    waitOneSecond();
  }
  
  @Generated
  @SneakyThrows
  private void waitOneSecond() {
    Thread.sleep(1000);
  }
}

My solution on this is to attempt to mock objectMapper to throw an unchecked exception(eg: RuntimeException) then the code flow will jump inside to catch block(generated by Lombok) and @SneakyThrows will be covered.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM