Модульное тестирование InterruptedException для ThreadPoolTaskExecutor с Mockito Spy - PullRequest
0 голосов
/ 21 сентября 2018

Я использую Spring ThreadPoolTaskExecutor для выполнения задач в нескольких потоках.Класс выглядит следующим образом:

    @Component
    public class LoadData {
    //... ...    

        @Inject
        private ThreadPoolTaskExecutor taskExecutor;

        public SomeData getData(Long id) {
            Future<SomeData> loadData = taskExecutor.submit(() -> {
                    //return methodToGetDataSynchronously(id);
                    return new SomeData();
            });
            try {
                SomeData data = loadData.get();
            } catch (InterruptedException | ExecutionException e) {
                logger.error("error");
                //some more processing for the error here
            }
            return data;
       }
  }

Чтобы иметь возможность провести модульное тестирование этого класса и охватить ветви InterruptedException и ExecutionException, я пробовал несколько подходов (используя Mockito Spy), ноне удалось успешно проверить это.

Класс модульного теста выглядит следующим образом:

@RunWith(MockitoJUnitRunner.class)
public class LoadDataTest {

    @InjectMocks
    private LoadData loadData;

    @Spy
    private ThreadPoolTaskExecutor spyTaskExecutor = new ThreadPoolTaskExecutor();

    @Before
    public void init() {
        MockitoAnnotations.initMocks(this);
        spyTaskExecutor.setCorePoolSize(1);
        spyTaskExecutor.setWaitForTasksToCompleteOnShutdown(true);
        spyTaskExecutor.initialize();
    }

    @Test
    public void testGetData_shouldThrowInterruptedException () {
        Mockito.when(spyTaskExecutor.submit(Matchers.<Callable<SomeData>>any())).thenAnswer(new Answer<Future<SomeData>>() {
            public Future<SomeData> answer(InvocationOnMock invocation) throws Throwable {
                Future<SomeData> future = Mockito.mock(FutureTask.class);
                when(future.isDone()).thenReturn(false, false, true);
                when(future.get()).thenThrow(new InterruptedException ());
                return future;
            }
        });

        SomeData result = null;
        result = loadData.getData(101L);
        //verify here that InterruptedException processing was performed
    }
}

Я использую Spy для ThreadPoolTaskExecutor, так как у меня есть другие методы в тесте, которыепроверяет фактическое поведение многопоточного исполнения.Когда я пытаюсь запустить тестовый метод, он бросает NullPointerException в шпионский шпион:

Mockito.when(spyTaskExecutor.submit(Matchers.<Callable<SomeData>>any()))...

Исключение:

java.lang.NullPointerException
    at java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:132)
    at org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor.submit(ThreadPoolTaskExecutor.java:320)
at com.company.LoadDataTest.testGetData_shouldThrowInterruptedException(LoadDataTest.java:20)

Я думаю, проблема может быть в том, как яя заглушаю шпиона Мокито.Однако я не уверен, что нахожусь на правильном пути, чтобы заглушить InterruptedException.Кто-нибудь получил пример того, как этого добиться?

Версии:

  jdk-1.8.0_72
  junit-4.12
  mockito-core-1.10.19
  spring-context-4.3.4.RELEASE

Примечание: это выдержка из реального кода.Фактический код выполняет много других вещей, и в него вводятся многие другие bean-компоненты - некоторые из них Mock в Test, некоторые Spy - в зависимости от того, что я тестирую.Я упомянул только ту часть, с которой я столкнулся здесь.

1 Ответ

0 голосов
/ 24 сентября 2018

Наконец-то разобрался с проблемой.Я был очень близок, просто использование Mockito Spy было немного странным.Вот рабочее решение:

@RunWith(MockitoJUnitRunner.class)
public class LoadDataTest {

    @InjectMocks
    private LoadData loadData;

    @Spy
    private ThreadPoolTaskExecutor spyTaskExecutor = new ThreadPoolTaskExecutor();

    @Before
    public void init() {
        MockitoAnnotations.initMocks(this);
        spyTaskExecutor.setCorePoolSize(1);
        spyTaskExecutor.setWaitForTasksToCompleteOnShutdown(true);
        spyTaskExecutor.initialize();
    }

    @Test
    public void testGetData_shouldThrowInterruptedException () {
        setupSpyTaskExecutorForException(new InterruptedException("junit"));

        SomeData result = loadData.getData(101L);
        //verify here that InterruptedException processing was performed
    }

    private void setupSpyTaskExecutorForException(Exception e) {
        Mockito.doAnswer(new Answer<Future<?>>() {
            public Future<?> answer(InvocationOnMock invocation) throws Throwable {
                Future<?> future = Mockito.mock(FutureTask.class);
                when(future.get()).thenThrow(e);
                return future;
            }
        }).when(spyTaskExecutor).submit(Matchers.<Callable<?>>any());
    }
}
...