Reputation: 155
I'm trying to understand mockito but I'm getting stuck, im trying to mock multiple objects using the @Mock annotation, but it will not mock them. It will only mock the first object (mockBoard). If I mock the BoardFactory myself using mock(Boardfactory.class) it will work. But i dont understand why it wont work in the @Mock?
@ExtendWith(MockitoExtension.class)
class MapParserTest {
//mocks just fine
@Mock private Board mockBoard;
//wont mock both factories, sets them to null
@Mock private BoardFactory mockBoardFactory;
@Mock private LevelFactory mockLevelFactory;
//this will work
//private BoardFactory mockBoardFactory = mock(BoardFactory.class);
private MapParser mapParser = new MapParser(mockLevelFactory, mockBoardFactory);
private List<Ghost> ghosts = new ArrayList<>();
private List<Square> startPositions = new ArrayList<>();
@Test
void testParseCharMatrix() {
//Arrange
char[][] mapMatrix = new char[1][];
mapMatrix[0] = new char[]{'#'};
//nullPointer exception thrown here
when(mockBoardFactory.createBoard(any(Square[][].class))).thenReturn(mockBoard);
//Act
mapParser.parseMap(mapMatrix);
//Assert
verify(mockLevelFactory).createLevel(mockBoard, ghosts, startPositions);
}}
Upvotes: 0
Views: 4475
Reputation: 10662
private MapParser mapParser = new MapParser(mockLevelFactory, mockBoardFactory);
Here, mockLevelFactory
and mockBoardFactory
will always be null, no matter if JUnit4, 5, @Rule
or @ExtendWith
. Why? Because that line gets called as soon as your test class is instantiated, long before Mockito had a chance to run and put mocks into your annotated variables:
The following lines get executed:
private MapParser mapParser = new MapParser(mockLevelFactory, mockBoardFactory);
private List<Ghost> ghosts = new ArrayList<>();
private List<Square> startPositions = new ArrayList<>();
Mockito creates the following mocks:
@Mock private Board mockBoard;
@Mock private BoardFactory mockBoardFactory;
@Mock private LevelFactory mockLevelFactory;
(some time later) The actual test method is called
This is why mockLevelFactory
and mockBoardFactory
are always null in your MapParser
. They are not null in your test, but they are null at the moment when you create your MapParser
.
The solution? Create the instance of your MapParser
later, for example in a @BeforeEach
method...
@BeforeEach
public void beforeEach() {
// This method gets called AFTER Mockito created the mocks
mapParser = new MapParser(mockLevelFactory, mockBoardFactory);
}
...or also simply at the start of your test method (but one could consider that bad style).
Upvotes: 2
Reputation: 30019
Are you sure the first field is actually initialized? Unless you run the test with MockitoJUnitRunner
, you need to initialize the annotated fields of the test class manually, for example like this:
@BeforeEach
public void initMocks() {
MockitoAnnotations.initMocks(this);
}
As a side note, even if the mocks are created correctly, then I'm note sure if the field mapParser
will be initialized correctly. It's likely that mocks are injected after the test class has been initialized, so you probably can't use mocked field in the constructor or in field initializers. You probably need to initialize that field in a @BeforeEach
method, like you had in the beginning.
Upvotes: 0