简体   繁体   English

带有@Builder 的Lombok @NonNull 注释未反映在测试覆盖率中

[英]Lombok @NonNull annotation with @Builder not reflecting in test coverage

I have come across an issue while testing lombok annotated class.我在测试带注释的class时遇到了一个问题。 Description:-描述:-

When we annotate a java class(POJO) with @Builder , and have certain instance variable with @NonNull constraints, while writing the test case to check for NullPointerException , we cannot instantiate the POJO with builder and expect it will evaluate against the null check.I delomboked the class and saw that the non null constraint flows inside the generated builder class itself which means a null pointer exception is thrown even before we construct the object.This is a correct behavior in some sense but I needed to know if I can test such a scenario.当我们使用 @Builder 注释 java 类(POJO),并且具有带有@Builder约束的某些实例变量@NonNull ,在编写测试用例以检查NullPointerException时,我们无法使用 builder 实例化POJO ,并期望它会根据 null 检查进行评估。 I delomboked the class and saw that the non null constraint flows inside the generated builder class itself which means a null pointer exception is thrown even before we construct the object.This is a correct behavior in some sense but I needed to know if I can test这样的场景。

@Builder
public class Sample {
    @NonNull
    private final String a;
    private final String b;
}

Now I need to test the case where NullPointerException is thrown in case 'a' is Null.现在我需要测试在“a”是 Null 的情况下抛出 NullPointerException 的情况。 For such a scenario I have 2 options:对于这种情况,我有 2 个选项:

  • Either I can create the Sample class with constructor - new Sample(null, null)我可以使用构造函数创建示例 class - new Sample(null, null)
  • Or I can create through builder - Sample.builder.a(null).build();或者我可以通过构建器创建 - Sample.builder.a(null).build();

My question is on the second part as first one will work just fine.我的问题在第二部分,因为第一个可以正常工作。 When I delombok this I will get something like:-当我delombok时,我会得到类似的东西:-

public class Sample {
    @NonNull
    private final String a;
    private final String b;

    Sample(@NonNull String a, String b) {
        this.a = a;
        this.b = b;
    }

    public static SampleBuilder builder() {
        return new SampleBuilder();
    }

    public static class SampleBuilder {
        private @NonNull String a;
        private String b;

        SampleBuilder() {
        }

        public SampleBuilder a(@NonNull String a) {
            this.a = a;
            return this;
        }

        public SampleBuilder b(String b) {
            this.b = b;
            return this;
        }

        public Sample build() {
            return new Sample(a, b);
        }

        public String toString() {
            return "Sample.SampleBuilder(a=" + this.a + ", b=" + this.b + ")";
        }
    }
}

Here if you see NullPointerException will be thrown inside SampleBuilder itself as it takes @NonNull arguments and constructor will never execute the condition to check for non null attribute due to which test coverage will fall.If we use @SuperBuilder , this will not happen as it does not take @NonNull in builder arguments.在这里,如果您看到 NullPointerException 将被抛出 SampleBuilder 本身,因为它需要@NonNull arguments 并且构造函数将永远不会执行条件来检查非 null 属性,因为测试覆盖率将会下降。如果我们使用@SuperBuilder ,这将不会发生在构建器 arguments 中不采用@NonNull

Not really sure what you are expecting, but the source code below can properly test the null check of both constructor and builder of Sample class.不太确定您在期待什么,但下面的源代码可以正确测试示例 class 的构造函数和生成器的null检查。

You can see it running at https://repl.it/repls/CleverWiryTruespace .您可以看到它在https://repl.it/repls/CleverWiryTruespace运行。

import lombok.NonNull;
import lombok.Builder;
import org.junit.Rule;
import org.junit.Test;
import org.junit.Before;
import org.junit.rules.ExpectedException;
import org.junit.runner.JUnitCore;

class Main {
  @Builder
  public static class Sample {
      @NonNull
      private final String a;
      private final String b;
  }

  public static class TestSample {
    @Rule
    public ExpectedException thrown = ExpectedException.none();

    @Before
    public void setUp() {
      thrown.expect(NullPointerException.class);
      thrown.expectMessage("a is marked non-null but is null");
    }

    @Test
    public void test1() {
      Sample s = new Sample(null, "abc");
    }

    @Test
    public void test2() {
      Sample.builder().a(null).build();
    }
  }

  public static void main(String[] args) {
    new JUnitCore().main(TestSample.class.getName());
  }
}

From the code we can see that if we want to trigger NPE at constructor level we need to leave the @NonNull parameter as empty rather than setting it to null which will trigger builder method level NPE.从代码中我们可以看到,如果我们想在构造函数级别触发 NPE,我们需要将 @NonNull 参数保留为空,而不是将其设置为 null,这将触发构建方法级别的 NPE。 If I build Sample object in the following manner it should suffice my case:-如果我以下列方式构建样本 object 就足够了:-

Sample sample = Sample.builder.b("b").build();

Here I am not explicitly setting parameter 'a' to NULL if I want to test NPE of 'a' at constructor level.如果我想在构造函数级别测试“a”的 NPE,这里我没有将参数“a”显式设置为 NULL。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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