我试图了解mockito,但我遇到了困难,我试图使用@Mock注释模拟多个对象,但它不会嘲笑它们。它只会模拟第一个对象(mockBoard)。 如果我使用mock(Boardfactory.class)自己模拟BoardFactory它会工作。但我不明白为什么它不会在@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);
}}
答案 0 :(得分:1)
private MapParser mapParser = new MapParser(mockLevelFactory, mockBoardFactory);
此处,mockLevelFactory
和mockBoardFactory
始终为空,无论是JUnit4,5,@Rule
还是@ExtendWith
。为什么?因为一旦你的测试类被实例化就会调用该行,很久之前Mockito就有机会运行并将模拟放入带注释的变量中:
执行以下行:
private MapParser mapParser = new MapParser(mockLevelFactory, mockBoardFactory);
private List<Ghost> ghosts = new ArrayList<>();
private List<Square> startPositions = new ArrayList<>();
Mockito创建了以下模拟:
@Mock private Board mockBoard;
@Mock private BoardFactory mockBoardFactory;
@Mock private LevelFactory mockLevelFactory;
(一段时间后)实际测试方法称为
这就是mockLevelFactory
中mockBoardFactory
和MapParser
总是为空的原因。它们在您的测试中不为空,但在您创建MapParser
时 为空。
解决方案?稍后创建MapParser
的实例,例如在@BeforeEach
方法...
@BeforeEach
public void beforeEach() {
// This method gets called AFTER Mockito created the mocks
mapParser = new MapParser(mockLevelFactory, mockBoardFactory);
}
......或者只是在测试方法的开头(但可以考虑那种糟糕的风格)。
答案 1 :(得分:0)
您确定第一个字段是否已实际初始化?除非您使用MockitoJUnitRunner
运行测试,否则您需要手动初始化测试类的带注释字段,例如:
@BeforeEach
public void initMocks() {
MockitoAnnotations.initMocks(this);
}
作为旁注,即使正确创建了模拟,我也要注意是否将正确初始化字段mapParser
。在测试类初始化之后,可能会注入模拟,因此您可能无法在构造函数或字段初始值设定项中使用模拟字段。您可能需要在@BeforeEach
方法中初始化该字段,就像您在开始时一样。