Как заглушить асинхронные вызовы с помощью mockito?

Предположим, у меня есть два класса, которые работают вместе, чтобы выполнить такой вызываемый объект:

public class blah {

@Autowired
private ExecutorServiceUtil executorServiceUtil;

@Autowired
private RestTemplate restClient;

public SomeReturnType getDepositTransactions(HttpHeaders httpHeaders) {

    ExecutorService executor = executorServiceUtil.createExecuter();
    try {
        DepositTransactionsAsyncResponse asyncResponse = getPersonalCollectionAsyncResponse( httpHeaders, executor);
        // do some processing 
        // return appropriate return type
    }finally {
        executorServiceUtil.shutDownExecutor(executor);
    }
}

Future<ResponseEntity<PersonalCollectionResponse>> getPersonalCollectionAsyncResponse( HttpHeaders httpHeaders, ExecutorService executor) {

    PersonalCollectionRequest personalCollectionRequest = getpersonalCollectionRequest(); // getPersonalCollectionRequest populates the request appropriately
    return executor.submit(() -> restClient.exchange(personalCollectionRequest, httpHeaders, PersonalCollectionResponse.class));
    }
}

public class ExecutorServiceUtil {

    private static Logger log = LoggerFactory.getLogger(ExecutorServiceUtil.class);

    public ExecutorService createExecuter() {
        return Executors.newCachedThreadPool();
    }

     public void shutDownExecutor(ExecutorService executor) {
            try {
                executor.shutdown();
                executor.awaitTermination(5, TimeUnit.SECONDS);
            }
            catch (InterruptedException e) {
                log.error("Tasks were interrupted");
            }
            finally {
                if (!executor.isTerminated()) {
                    log.error("Cancel non-finished tasks");
                }
                executor.shutdownNow();
            }
        }

}

Как я могу использовать Mockito, чтобы заглушить ответ и немедленно вернуть его?

Я пробовал следующее, но мой Innovcation.args () возвращает [null]

PowerMockito.when(executor.submit(Matchers.<Callable<ResponseEntity<OrxPendingPostedTrxCollectionResponseV3>>> any())).thenAnswer(new Answer<FutureTask<ResponseEntity<OrxPendingPostedTrxCollectionResponseV3>>>() {

            @Override
            public FutureTask<ResponseEntity<OrxPendingPostedTrxCollectionResponseV3>> answer(InvocationOnMock invocation) throws Throwable {
                Object [] args = invocation.getArguments();
                Callable<ResponseEntity<OrxPendingPostedTrxCollectionResponseV3>> callable = (Callable<ResponseEntity<OrxPendingPostedTrxCollectionResponseV3>>) args[0];
                callable.call();
                        return null;
                    }
                });

person Norbert    schedule 12.04.2017    source источник
comment
С предложением @ GhostCat я смог заставить вызовы возвращаться синхронно и позволил мне удалить логику ответа.   -  person Norbert    schedule 14.04.2017


Ответы (1)


Вы делаете это, не используя свой ExecutorServiceUtil в тестовом коде. Я имею в виду: вы предоставляете имитацию этого класса util в свой производственный код!

И этот макет действительно возвращает «службу-исполнитель того же потока»; вместо «реальной службы» (на основе пула потоков). Написание такого же исполнителя-потока на самом деле просто - см. здесь.

Другими словами: здесь вам нужны два разных модульных теста:

  1. Вы пишете модульные тесты для своего ExecutorServiceUtil класса изолированно; убедитесь, что он выполняет то, что должен делать (где я думаю: проверка того, что он возвращает ненулевое значение ExecutorService, почти достаточно!)
  2. Вы пишете модульные тесты для своего blah класса ... которые используют фиктивный сервис. И внезапно все ваши проблемы с "асинхронным" уходят; потому что асинхронная часть исчезает в воздухе.
person GhostCat    schedule 13.04.2017