Spring Boot @Async аннотация и MockRestServiceServer - PullRequest
0 голосов
/ 22 ноября 2018

Я использую Spring Boot 2.0.6 и Java 10. Я сделал следующий сервис, который работает только с внешним API отдыха с помощью RestTemplate.

@Service
@Slf4j
public class DbApiClientImpl implements DbApiClient {

  private final String URL_DELIMITER = "/";
  private RestTemplate restTemplate;
  private String url;

  public DbApiClientImpl(
      RestTemplateBuilder restTemplate,
      @Value("${dbapi.namespace}") String namespace,
      @Value("${dbapi.url}") String uri,
      @Value("${dbapi.username}") String username,
      @Value("${dbapi.password}") String password) {

  this.restTemplate = restTemplate.basicAuthorization(username, 
                      password).build();
  this.url = namespace.concat(uri);
}

   @Override
   @Async("asyncExecutor")
   public Merchant fetchMerchant(String id) {
       ResponseEntity<Merchant> response = 
        restTemplate.getForEntity(url.concat(URL_DELIMITER).concat(id), 
        Merchant.class);
   return response.getBody();
   }
}

И следующий тест с использованием MockeRestServiceServer:

@RunWith(SpringRunner.class)
@RestClientTest(value = {DbApiClient.class})
public class DbApiClientTest {

   private static final String TEST_NAME = "test";
   private static final String TEST_NAME_BAD_REQUEST = "test- 
   1";
   private static final String TEST_NAME_SERVER_ERROR = 
  "test-2";

   @Autowired DbApiClient dbApiClient;

   @Value("${dbapi.namespace}")
   private String namespace;

   @Value("${dbapi.url}")
   private String dbApiUrl;

   @Autowired private MockRestServiceServer mockServer;

   @Autowired private ObjectMapper objectMapper;

   @Test
   public void test() throws 
   JsonProcessingException, IOException {
      Merchant mockMerchantSpec = populateFakeMerchant();
      String jsonResponse = 
          objectMapper.writeValueAsString(mockMerchantSpec);
      mockServer
         .expect(manyTimes(), 
           requestTo(dbApiUrl.concat("/").concat(TEST_NAME)))
         .andExpect(method(HttpMethod.GET))
         .andRespond(withSuccess(jsonResponse, 
                       MediaType.APPLICATION_JSON));

       assertNotNull(dbApiClient.fetchMerchant(TEST_NAME));
  }

Дело в том, что я получаю следующее исключение, когда запускаю тест: «Не ожидается дальнейший запрос HTTP GET http://localthost... Excuted»

Так что, похоже, @Asyncborking MockerServerService response ... Кроме того, если я прокомментирую аннотацию @Async, все работает отлично, и я получаю весь тест зеленым.

Заранее спасибо за ваши комментарии.

Обновление:

Согласно комментарию @ M.Deinum.Я удалил CompletableFuture из службы, но все равно получаю то же исключение.

1 Ответ

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

Проблема в вашем коде, а не в вашем тесте.

Если вы прочитаете документацию ( JavaDoc ) AsyncExecutionInterceptor, вы увидите упоминание о том, что в качестве возвращаемого типа поддерживается только void или Future.Вы возвращаете простой объект, который внутренне рассматривается как void.

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

Чтобы исправить, исправьте сигнатуру вашего метода и верните Future<Merchant>, чтобы вы могли заблокировать и дождаться результата.

@Override
@Async("asyncExecutor")
public Future<Merchant> fetchMerchant(String id) {
   ResponseEntity<Merchant> response = 
    restTemplate.getForEntity(url.concat(URL_DELIMITER).concat(id), 
    Merchant.class);
   return CompletableFuture.completedFuture(response.getBody());
}

Теперь ваш вызывающий код знает о возвращенном Future, а также о коде Spring Async.Теперь в вашем тесте вы можете теперь вызвать get для возвращенного значения (возможно, с таймаутом для получения ошибки, если что-то не получится).Чтобы проверить результат.

...