Mockito ArgumentCaptor не захватывает аргументы в блоке catch - PullRequest
2 голосов
/ 14 апреля 2020

Я написал этот сервис

public class FirstService {

    private final SecondService secondService;

    public FirstService(SecondService secondService) {
        this.secondService = secondService;
    }

    public void hz() throws Exception {
        try {
            methodThrowsException();
        } catch (Exception e){
            secondService.handleErrorMessage(e.getMessage());
            throw e;
        }
    }

    private void methodThrowsException() throws Exception {
        throw new Exception("message");
    }
}

И этот сервис:

public class SecondService {
    public void handleErrorMessage(String message) {}
}

Мне нужно убедиться, что handleErrorMessage был вызван. Я написал тест:

import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;

import static org.junit.Assert.*;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;

public class FirstServiceTest {
    private FirstService firstService;
    private SecondService secondService;

    @Before
    public void setUp() {
        secondService = mock(SecondService.class);
        firstService = new FirstService(secondService);
    }

    @Test(expected = Exception.class)
    public void hz() throws Exception {
        firstService.hz();
        ArgumentCaptor<String> argumentCaptor = ArgumentCaptor.forClass(String.class);
        verify(secondService).handleErrorMessage(argumentCaptor.capture());
        String value = argumentCaptor.getValue();

        assertEquals("message", value);
    }
}

Тестовый заезд. Но если я изменю assertEquals("message666", value);, он все равно пройдет. Если я не выбрасываю исключение в блоке catch - ArgumentCaptor перехватывает аргумент, но когда я выкидываю исключение, оно не работает.

1 Ответ

4 голосов
/ 14 апреля 2020

Ваш тест аннотирован: @Test(expected = Exception.class)

Это означает, что тест будет пройден, если Exception (или любой подкласс) поднимется до верхнего уровня. Это происходит в первой строке вашего теста:

    firstService.hz();

Вот почему он проходит. К сожалению, это исключение означает, что остальная часть вашего теста никогда не запускается, так как это исключение распространяется вверх и за пределы вашего метода теста.

Немного некрасиво, но этот фрагмент делает то, что вы хотите:

    @Test
    public void hz() throws Exception {

        try {
            firstService.hz();

            // If we get here, then we didn't throw an exception - fail
            Assert.fail();
        } catch (Exception ex) {
            // Exception was expected - disregard and continue
            // no-op
        }
        ArgumentCaptor<String> argumentCaptor = ArgumentCaptor.forClass(String.class);
        verify(secondService).handleErrorMessage(argumentCaptor.capture());
        String value = argumentCaptor.getValue();

        assertEquals("message", value);
    }

Вышеприведенный метод запускает ваш метод и перехватывает исключение (и завершается ошибкой, если вы не получили ожидаемое исключение). Затем он продолжается и запускает оставшуюся часть теста.

JUnit 5 предоставляет немного более чистый способ, но вам придется выполнить миграцию:

    @Test
    public void hz() throws Exception {

        Assertions.assertThrows(Exception.class, () -> firstService.hz());

        ArgumentCaptor<String> argumentCaptor = ArgumentCaptor.forClass(String.class);
        verify(secondService).handleErrorMessage(argumentCaptor.capture());
        String value = argumentCaptor.getValue();

        assertEquals("asdf", value);
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...