Skip to content
Advertisement

Writing unit test for @Nonnull annotated parameter

I have a method like this one:

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

I would like to write a unit test to make sure foo() throws an NPE when value is null but I can’t since the compiler refuses to compile the unit test when static null pointer flow analysis is enabled in IDE.

How do I make this test compile (in Eclipse with “Enable annotation-based null analysis” enabled):

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

Note: In theory the static null pointer of the compiler should prevent cases like that. But there is nothing stopping someone from writing another module with the static flow analysis turned off and calling the method with null.

Common case: Big messy old project without flow analysis. I start with annotating some utility module. In that case, I’ll have existing or new unit tests which check how the code behaves for all the modules which don’t use flow analysis yet.

My guess is that I have to move those tests into an unchecked module and move them around as I spread flow analysis. That would work and fit well into the philosophy but it would be a lot of manual work.

To put it another way: I can’t easily write a test which says “success when code doesn’t compile” (I’d have to put code pieces into files, invoke the compiler from unit tests, check the output for errors … not pretty). So how can I test easily that the code fails as it should when callers ignore @Nonnull?

Advertisement

Answer

Hiding null within a method does the trick:

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());
}

The above compiles fine (and yes, double-checked – when using foo(null) my IDE gives me a compile error – so “null checking” is enabled).

In contrast to the solution given via comments, the above has the nice side effect to work for any kind of parameter type (but might probably require Java8 to get the type inference correct always).

And yes, the test passes (as written above), and fails when commenting out the Objects.requireNonNull() line.

Advertisement