代码之家  ›  专栏  ›  技术社区  ›  Aaron Digulla

为@Nonnull注释参数编写单元测试

  •  8
  • Aaron Digulla  · 技术社区  · 7 年前

    我有这样一种方法:

     public void foo(@Nonnull String value) {...}
    

    我想写一个单元测试来确保 foo() 在以下情况下抛出NPE value null 但我不能,因为当IDE中启用静态空指针流分析时,编译器拒绝编译单元测试。

    @Test(expected = NullPointerException.class)
    public void test() {
         T inst = ...
         inst.foo(null);
    }
    

    不要 使用流分析 然而 .

    我的猜测是,我必须将这些测试转移到一个未经检查的模块中,并在传播流分析时移动它们。这很管用,也很符合哲学,但这需要大量的体力劳动。

    换句话说:我不能轻松编写一个测试,它说“代码无法编译时成功”(我必须将代码片段放入文件中,从单元测试中调用编译器,检查输出是否有错误……这不太好)。那么我该怎么测试呢 容易地 @Nonnull

    5 回复  |  直到 7 年前
        1
  •  8
  •   Aaron Digulla    7 年前

    躲藏 null

    public void foo(@NonNull String bar) {
        Objects.requireNonNull(bar);
    }
    
    /** Trick the Java flow analysis to allow passing <code>null</code>
     *  for @Nonnull parameters. 
     */
    @SuppressWarnings("null")
    public static <T> T giveNull() {
        return null;
    }
    
    @Test(expected = NullPointerException.class)
    public void testFoo() {
        foo(giveNull());
    }
    

    以上编译很好(是的,在使用时进行了双重检查) foo(null)

    与通过评论给出的解决方案不同,上述方法有很好的副作用 任何 一种参数类型(但可能需要Java8才能始终正确地进行类型推断)。

    Objects.requireNonNull() 线

        2
  •  2
  •   Aaron Digulla    7 年前

    为什么不使用普通的旧反射?

    try {
        YourClass.getMethod("foo", String.class).invoke(someInstance, null);
        fail("Expected InvocationException with nested NPE");
    } catch(InvocationException e) {
        if (e.getCause() instanceof NullPointerException) {
            return; // success
        }
        throw e; // let the test fail
    }
    

        3
  •  1
  •   Sam Gruse    3 年前

    使用Jupiter断言中的assertThrows,我能够测试这一点:

    public MethodName(@NonNull final param1 dao) {....
    
    assertThrows(IllegalArgumentException.class, () -> new MethodName(null));
    
        4
  •  0
  •   LONGHORN007    7 年前

    在这里,合同设计就出现了。不能向用notNull参数注释的方法提供null值参数。

        5
  •  0
  •   Aaron Digulla    7 年前

    null

    private String nullValue = ""; // set to null in clearNullValue()
    @Before
    public void clearNullValue() {
        nullValue = null;
    }
    
    @Test(expected = NullPointerException.class)
    public void test() {
         T inst = ...
         inst.foo(nullValue);
    }
    

    clearNullValue() 被调用,并且必须假设字段不是 无效的