TLDR; check that you haven’t redeclared a field as a variable in a setup method
FAQ - why does my code throw a null pointer exception - common reason #1 Redeclaration
- Using
@BeforeClass
or@Before
can setup data for use in tests - Any ‘variables’ we instantiate need to be ‘fields’ rather than variables
- We want to instantiate them in the setup method rather than redeclare them
Example of the Problem
e.g.
I know I will use an Adder
in my test so I create it as a field:
public class WhyCodeThrowsNullPointerExceptionTest {
Adder adder;
I don’t want to re-instantiate it each time so I make an @BeforeClass
method to instantiate it:
@BeforeClass
public static void setupAdder(){
Adder adder = new Adder();
}
I just made a Semantic coding error. This won’t be caught by a compiler, but it will cause my @Test
to fail with a Null Pointer Exception.
@Test
public void canAddTwoPlusTwo(){
Assert.assertEquals(4,adder.add(2,2));
}
The above test will fail with a NullPointerException
java.lang.NullPointerException
at com.javafortesters.faq.nullpointerexception.
WhyCodeThrowsNullPointerExceptionTest.canAddTwoPlusTwo
(WhyCodeThrowsNullPointerExceptionTest.java:29)
...
What Went Wrong?
In the setup method I really wanted to assign a value to the field, instead I created an new variable with the same name.
Adder adder = new Adder();
I really wanted:
adder = new Adder();
and to support that, the field really needs to be declared as static
static Adder adder;
How to avoid?
IDE Syntax Highlighting
If I was editing this in an IDE, then I would see that the adder
in the following line is never used :
Adder adder = new Adder();
It will be coloured grey or some other IDE indication.
static
methods need static
fields
In order for the field to be used in the static method it needed to be static.
If I had used it in the setup method:
Adder adder;
@BeforeClass
public static void setupAdder(){
adder = new Adder();
}
Then I would have seen a syntax error in the code because:
Non-static field 'adder' cannot be referenced from a static context
Refactor to fields
Had I written the @Test
code first then I would have started with:
@Test
public void canAddTwoPlusTwo(){
Adder adder = new Adder();
Assert.assertEquals(4,adder.add(2,2));
}
Then, when I created a second @Test
I would have seen duplication, and I might have chosen to remove that duplication by creating adder
as a field, and I could have done that with an automated refactoring of Extract to field where initialized as ‘field declaration’:
Which might have generated the following code:
private final Adder adder = new Adder();
- this removes the need for an
@BeforeClass
or@Before
construct entirely
I could have refactored as initialized in constructor:
private final Adder adder;
public WhyCodeThrowsNullPointerExceptionTest() {
adder = new Adder();
}
- this removes the need for an
@BeforeClass
or@Before
construct entirely
I might have looked at the above code and decided that I needed an @BeforeClass
or @Before
construct to make the code readable, in which case I could have added the method but I don’t think I would have declared a new variable because I have a working code example that I’m moving.
In General
- Try to write one test at a time so that if you have a problem it is easier to identify where the problem is
- Try to write working isolated tests and then refactor to a more general solution when you need it - that way, you know it was working, so you just have to work backwards to find out what went wrong
- Try to use automated IDE refactoring rather than move code around manually
- Use the IDE syntax highlighting to help spot any issues
If you want to experiment with code that recreates this problem then have a look at WhyCodeThrowsNullPointerExceptionTest.java in learn-java-examples