Я столкнулся с проблемой при попытке выполнить модульное тестирование вызова функции. Вызов не удался для вызова метода 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
    }   
}
0
nnrr 15 Авг 2019 в 21:23

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
}
0
nnrr 16 Авг 2019 в 21:54

Не используйте 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();
}
1
Maciej Kowalski 15 Авг 2019 в 18:45