Я пытаюсь понять mockito, но я застреваю, я пытаюсь издеваться над несколькими объектами с помощью аннотации @Mock, но он не будет издеваться над ними. Он будет издеваться только над первым объектом (mockBoard). Если я сам издеваюсь над BoardFactory, используя mock (Boardfactory.class), он будет работать. Но я не понимаю, почему это не работает в @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);
}}
@BeforeEach, похоже, подразумевает, что вы используете JUnit 5, но эта версия больше не использует @Rule. Если вы используете JUnit 5, вы должны аннотировать свой класс с помощью @ExtendWith(MockitoExtension.class). Правила являются частью JUnit 4. Конечно, это не объясняет, почему работает первый @Mock.




Вы уверены, что первое поле действительно инициализировано? Если вы не запускаете тест с MockitoJUnitRunner, вам необходимо вручную инициализировать аннотированные поля тестового класса, например, следующим образом:
@BeforeEach
public void initMocks() {
MockitoAnnotations.initMocks(this);
}
В качестве примечания, даже если макеты созданы правильно, я уверен, что поле mapParser будет правильно инициализировано. Вероятно, что макеты внедряются после инициализации тестового класса, поэтому вы, вероятно, не сможете использовать макет поля в конструкторе или в инициализаторах полей. Вам, вероятно, потребуется инициализировать это поле в методе @BeforeEach, как в начале.
а) Кажется, это JUnit 45, поэтому нет Runner. б) Перед одним из его изменений у него было MockitoRule, которое должно обо всем позаботиться.
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);
}
... или просто в начале вашего метода тестирования (но это можно считать плохим стилем).
Если вы используете JUnit 4, не могли бы вы также добавить переменную класса @InjectMocks private MapParser mapParser;, которая будет вводить зависимости? Тогда вам вообще не понадобится этот метод.
@Mockимитирует аннотированное поле. Опубликуйте полный минимальный пример, воспроизводящий проблему. Имитация списка не имеет особого смысла: почему бы не использовать настоящий список? Создать такой - нетрудно, не правда ли? И почему вы делаете moc mapParser, а потом создаете немодельный? Это тоже не имеет смысла.