Spring Boot @Async批注和MockRestServiceServer

时间:2018-11-22 19:41:36

标签: java spring asynchronous resttemplate

我正在使用Spring Boot 2.0.6和Java10。我做了以下服务,仅使用RestTemplate命中了外部rest api。

@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));
  }

以及使用MockeRestServiceServer进行的以下测试:

<template>
    <Page class="page">
        <ActionBar title="Home" class="action-bar" />
        <ScrollView>
            <StackLayout class="home-panel">
                <Widget v-for="widget in widgets" :widgetName="widget.name"/>
                <Button text="Add widget" class="btn btn-primary" @tap="addWidget" />
            </StackLayout>
        </ScrollView>
    </Page>
</template>

<script>
    import Widget from "./Widget";
    export default {
        data() {
            return {
                widgets: [{
                    name: "widget1"
                }, {
                    name: "widget2"
                }]
            };
        },
        components: {
            Widget
        },
        methods: {
            addWidget() {
                this.widgets.push(
                    {
                        name: `widget${this.widgets.length+1}`
                    }
                )
            },
            removeWidget(name){
                console.log('removing widget');
                this.widgets.forEach( (i, widget) => {
                    if(widget.name === name){
                        this.widgets.splice(i,1);
                    }
                })
            }
        }
    };
</script>

问题是,当我运行测试“没有进一步的请求预期的HTTP GET http://localthost ...已执行”时,我得到以下异常

似乎@Async使MockerServerService响应令人厌烦... 另外,如果我对@Async批注进行了注释,则一切正常,并且所有测试都变为绿色。

谢谢您的评论。

更新:

根据@ M.Deinum的评论。我从服务中删除了CompletableFuture,但仍然遇到相同的异常。

1 个答案:

答案 0 :(得分:0)

问题在于您的代码而不是您的测试。

如果您阅读AsyncExecutionInterceptor的文档(the JavaDoc),将会看到提到仅支持voidFuture作为返回类型的提示。您将返回一个普通对象,该对象在内部被视为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(如果超时,则超时,如果出现故障则收到错误)。检查结果。