Имитация переменной при наличии двух переменных одного типа

#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 , который будет использовать этот второй макет.