#java #unit-testing #junit #mockito
#java #модульное тестирование #junit #mockito
Вопрос:
У меня есть следующий класс:
public class FinanceService {
private BookingDao bookingMasterDao;
private BookingDao bookingDao;
public void createRecords(FinancialSummary financialSummary) {
BookingEntity booking = bookingDao.loadById(1);
//do stuff with this booking object
}
}
Я хочу издеваться над bookingDao, поэтому у меня есть следующий тестовый класс junit
public class FinanceServiceTest {
@Mock
private BookingDao bookingDao;
@InjectMocks
private FinanceService financeService = new FinanceService();
@Before
public void before() { MockitoAnnotations.initMocks(this);}
@Test
public void testCreateRecords() {
BookingEntity bookingEntity = new BookingEntity();
FinancialSummary financialSummary = new FinancialSummary();
when(bookingDao.loadById(anyInt())).thenReturn(bookingEntity);
financeService.createRecords(financialSummary);
}
}
Это вызывает исключение нулевого указателя, потому что bookingMasterDao
издевается, но bookingDao
это не так. Если я поменяю местами эти две в FinanceService, тогда это сработает. Похоже, что Mockito издевается над первой переменной, которая соответствует этому типу.
Есть ли способ проинструктировать Mockito, присвоив ему имя переменной, которую вы хотите имитировать?
Комментарии:
1. замена @InjectMocks на ручное внедрение должна обойти проблему
2. Я согласен с RC, у переменных тоже есть чувства! лол
3. Когда вы говорите о ручном внедрении, вы имеете в виду передачу макетов как части конструктора FinanceService?
4. Я только что протестировал ваш код, и он сработал на моей стороне
5. Какую версию mockito вы используете?
Ответ №1:
Из javadoc:
Примечание 1: Если у вас есть свойства с одинаковым типом (или одинаковым удалением), лучше называть все
@Mock
аннотированные поля соответствующими свойствами, иначе Mockito может запутаться и внедрение не произойдет.
Итак, вы должны назвать свои макеты, см. Mock.html#name()
(примечание: как следствие, вы не можете использовать один и тот же макет для обоих DAO).
Комментарии:
1. Я попробовал это, и это не сработало. Для меня это не имело никакого значения.
2. «не сработало» — это немного широко, может быть, вы могли бы предоставить код, который вы пробовали (в вашем вопросе)
Ответ №2:
Просто, просто объявите два макета, по одному для каждого целевого поля DAO:
public class FinanceServiceTest {
@Mock BookingDao bookingMasterDao;
@Mock BookingDao bookingDao;
...
}
Комментарии:
1. Это действительно работает, и я использовал обходной путь. Просто кажется немного странным объявлять переменную, которую я никогда не использую.
2. Да, но наверняка есть метод, в
FinanceService
котором используетсяbookingMasterDao
. Итак, вы можете добавить тест вFinanceServiceTest
, который будет использовать этот второй макет.