Я столкнулся с проблемой при попытке выполнить модульное тестирование вызова функции. Вызов не удался для вызова метода void messageProducer.sendMessage()
, даже если он был заглушен.
Ниже приведен упрощенный снимок моего кода. Я использую заглушку doAnswer () для насмешки над методом void (на основе предыдущих ответов о StackOverflow).
Я даже попробовал другие варианты заглушек doThrow()
и doNothing()
, но они также не работают с тем же NPE при вызове метода заглушки :(.
Цените, если кто-то может предложить решение / обходной путь. Большое спасибо.
Тестовый класс
// Test class
@RunWith(MockitoJUnitRunner.class)
public class RetriggerRequestTest {
@Mock
private MessageProducer messageProducer;
@InjectMocks
private MigrationRequestServiceImpl migrationRequestService;
@Before
public void init() {
MockitoAnnotations.initMocks(this);
}
@Test
public void sendRetriggerRequest() throws Exception {
// Below two stubbings also not Work, NPE encountered!
//doNothing().when(messageProducer).sendMessage(any(), anyLong());
//doThrow(new Exception()).doNothing().when(messageProducer).sendMessage(any(), anyLong());
doAnswer(new Answer<Void>() {
public Void answer(InvocationOnMock invocation) {
Object[] args = invocation.getArguments();
System.out.println("called with arguments: " + Arrays.toString(args));
return null;
}
}).when(messageProducer).sendMessage(any(EMSEvent.class), anyLong());
try {
// Gets Null pointer exception
migrationRequestService.retriggerRequest(emsRetriggerRequest);
}
catch (Exception ex) {
fail(ex.getMessage());
}
}
Тестируемый класс реализации, вызов метода-заглушки из этого класса выбрасывает NPE, как указано в комментариях к коду
@Service
@Transactional
public class MigrationRequestServiceImpl implements MigrationRequestService {
@Autowired
MessageProducer messageProducer;
@Override
public void retriggerRequest(EMSRetriggerRequestData emsRetriggerRequestData) throws EMSException {
// Does a bunch of things
submitTaskScheduledEventsToQueue(taskList);
}
private void submitTaskScheduledEventsToQueue(List<Task> taskList) {
System.out.println("Debugging 1...");
taskList.stream().forEach(task -> {
System.out.println("Debugging 2...");
Map<String, Object> detailsMap = new HashMap<String, Object>();
EMSEvent event = new EMSEvent(EMSEventType.TASK_SCHEDULED);
event.setDetails(detailsMap);
LOGGER.info(ContextRetriever.getServiceContext(), ContextRetriever.getRequestContext(), "*** Re-submitting Task: *** " + task.getId());
// ****Gives a null pointer exception here****
messageProducer.sendMessage(event, eventsConfigProperties.getScheduledEventDelay());
});
System.out.println("Debugging 3...");
}
}
Класс AutoWired, который вводится в тестовый класс и метод которого выбрасывает NPE.
@Service
public class MessageProducer {
private static final Logger logger = LoggerFactory.getLogger(MessageProducer.class);
private final RabbitTemplate rabbitTemplate;
@Autowired
public MessageProducer(RabbitTemplate rabbitTemplate) {
this.rabbitTemplate = rabbitTemplate;
}
public void sendMessage(EMSEvent emsEvent, Long delay) {
// code to send message to RabbitMQ here
}
}
2 ответа
Спасибо Мацей за ответ. На самом деле я не хочу ничего делать с аргументами, мне просто нужно пропустить вызов этого метода. Я просто использовал doAnswer с некоторым фиктивным кодом, поскольку doNothing () или doThrow () не работали с этим методом.
Однако я смог решить проблему. Один из компонентов Autowired (eventsConfigProperties) для класса, который был внедрен с помощью Mocks (MigrationRequestServiceImpl), не подвергался насмешке в тестовом классе! Спасибо @daniu за указание на это.
Трассировка стека от Mockito не очень помогла в отладке проблемы, она просто дала исключение нулевого указателя прямо при вызове метода, что заставило меня подумать, что могут быть другие проблемы!
Прошу прощения за ошибку, моя плохая, но спасибо и полезная информация об ArgumentCaptor, возможно, она понадобится для дальнейшего тестирования!
Пришлось добавить эту запись, которая была автоматически подключена к классу MigrationRequestService.
// Test class
@RunWith(MockitoJUnitRunner.class)
public class RetriggerRequestTest {
@Autowired
EventsConfigProperties eventsConfigProperties;
// Other declarations
}
Не используйте doAnswer, если вы просто хотите захватить аргументы и обработать / проверить их каким-либо образом. У Mockito есть определенная функция ArgumentCaptor
, которая предназначена именно для этого. Используя его, вам не нужно будет торговаться с этим методом void, как вы это делаете:
@Mock private MessageProducer messageProducer;
@Captor private ArgumentCaptor<Event> eventCaptor;
@Captor private ArgumentCaptor<Long> longCaptor;
@InjectMocks
private MigrationRequestServiceImpl migrationRequestService;
@Test
public void sendRetriggerRequest() throws Exception {
// When
migrationRequestService.retriggerRequest(emsRetriggerRequest);
// Then
verify(messageProducer).sendMessage(eventCaptor.capture(), longCaptor.capture());
Event e = eventCaptor().getValue();
Long l = longCaptor().getValue();
}
Похожие вопросы
Новые вопросы
java
Java — это высокоуровневый объектно-ориентированный язык программирования. Используйте этот тег, если у вас возникли проблемы с использованием или пониманием самого языка. Этот тег часто используется вместе с другими тегами для библиотек и/или фреймворков, используемых разработчиками Java.