Reputation: 12710
import org.junit.Test;
import edu.umd.cs.findbugs.annotations.DefaultAnnotation;
import edu.umd.cs.findbugs.annotations.NonNull;
@DefaultAnnotation(NonNull.class)
public class FooTest {
private Foo foo;
@Before
public void setUp() throws ParseException {
foo = ...;
}
@Test
public void testScenario1() {
foo.getId();
...
}
}
This causes findbugs to fail with:
NP: Nonnull field foo is not initialized
by new FooTest( (NP_NONNULL_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR)
Why is that? Does FindBugs not see that this is a junit test? (and therefore setUp() is called before executing each test)
One workaround is to add this class annotation:
@SuppressWarnings(
value="NP_NONNULL_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR",
justification="it is initialized in setUp()")
but that's not very nice. any better idea?
Upvotes: 1
Views: 6115
Reputation: 718738
Why is that? Does FindBugs not see that this is a junit test? (and therefore setUp() is called before executing each test)
Basically, yes. It is pretty obvious that FindBugs doesn't have special knowledge of JUnit test cases and how they work. (I'm a little surprised that you are even running FindBugs over your unit tests ...)
One workaround is to add this class annotation ... Any better idea?
It is simpler to explicitly initialize the field to null
. That will should satisfy FindBugs.
Yes, I hesitated to add NonNull annotations in the tests; but the tests themselves can contain bugs, so why not? Why not running FindBugs over the unit tests?
Because of problems like this!
Unit tests are qualitatively different to ordinary code. For instance, if the foo
field was accidentally left null
, then the worst that can happen is that the unit test will crash, you will spot the bug and fix it. It is not going to directly break production code, and will only have any impact at all if you are in the habit of ignoring failed unit tests.
I cannot initialize foo to null, since it is defined as NonNull (by the DefaultAnnotation)
Well according to TimK's answer, that means that foo
MUST be non-null after the constructor has finished executing. Given that you have specified that invariant for your entire codebase (including the testcases) you must either stick to it, or add an exception.
One kludge might be to create a dummy Foo
instance, and use that to initialize foo
. But it is more straightforward to just to add the SuppressWarnings ...
Frankly, you need to think a bit more deeply about what you are trying to achieve with FindBugs. Running it on your unit tests seems to be creating more problems than it solves.
Upvotes: 2
Reputation: 4835
The annotation "@DefaultAnnotation(NonNull.class)" means that foo is treated like it is annotated with @NonNull. That means foo is not allowed to be null during its lifetime. In your test it is null between the time the class is instantiated and the time setUp is called. So FindBugs is correctly reporting the problem.
Upvotes: 1
Reputation: 942
Could you possibly paste a real snippet that gives you the same warning and not the sample you gave?
The reason being is that I ran into this exact findbugs situation yesterday, but it was because of a typo:
public class FooTest {
private Foo foo;
@Before
public void setUp() throws ParseException {
Foo foo = ...;
}
You will notice I have Foo foo
. This defined a local method instance of foo and initializes it instead of initializing the private class attribute.
I know you are not doing that in your code snippet above but I am wondering if your real code in your project is making this mistake. Its a simple typo to check for.
Upvotes: 0