首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Spring MockRestServiceServer处理对同一URI的多个请求(自动发现)

Spring MockRestServiceServer处理对同一URI的多个请求(自动发现)
EN

Stack Overflow用户
提问于 2015-06-08 23:49:50
回答 2查看 38.6K关注 0票数 26

假设我正在为一个REST服务A编写Spring集成测试。这个服务反过来访问另一个REST服务B,并获得一个要访问REST服务C的URI列表。这是一种自动发现模式。我想使用MockRestServiceServer模拟B和C响应。

现在来自B的响应是一个URI列表,它们都非常相似,为了便于示例,我们假设B的响应是这样的:

代码语言:javascript
复制
{
    uris: ["/stuff/1.json", "/stuff/2.json", "/stuff/39.json", "/stuff/47.json"]
}

简单地说,服务A会将它们中的每一个附加到服务C的基本URL上,并发出这些请求。

模拟B很容易,因为它只有一个请求。

模拟C是一件麻烦的事情,因为我必须模拟每个单独的URI以获得适当的模拟响应。我想让它自动化!

因此,首先我编写自己的匹配器,匹配的不是完整的URL,而是其中的一部分:

代码语言:javascript
复制
public class RequestContainsUriMatcher implements RequestMatcher {
    private final String uri;

    public RequestContainsUriMatcher(String uri){
        this.uri = uri;
    }

    @Override
    public void match(ClientHttpRequest clientHttpRequest) throws IOException, AssertionError {
        assertTrue(clientHttpRequest.getURI().contains(uri));
    }
}

这很好用,因为现在我可以这样做:

代码语言:javascript
复制
public RequestMatcher requestContainsUri(String uri) {
    return new RequestContainsUriMatcher(uri);
}

MockRestServiceServer.createServer(restTemplate)
            .expect(requestContainsUri("/stuff"))
            .andExpect(method(HttpMethod.GET))
            .andRespond(/* I will get to response creator */);

现在,我需要的是一个知道完整的请求URL和模拟数据所在位置的响应创建器(我将把它作为json文件放在test resources文件夹中):

代码语言:javascript
复制
public class AutoDiscoveryCannedDataResponseCreator implements ResponseCreator {
    private final Function<String, String> cannedDataBuilder;

    public AutoDiscoveryCannedDataResponseCreator(Function<String, String> cannedDataBuilder) {
        this.cannedDataBuilder = cannedDataBuilder;
    }

    @Override
    public ClientHttpResponse createResponse(ClientHttpRequest clientHttpRequest) throws IOException {
        return withSuccess(cannedDataBuilder.apply(requestUri), MediaType.APPLICATION_JSON)
                    .createResponse(clientHttpRequest);
    }
}

现在事情很简单,我必须编写一个构建器,它将请求URI作为字符串,并将模拟数据作为字符串返回!非常出色!

代码语言:javascript
复制
public ResponseCreator withAutoDetectedCannedData() {
    Function<String, String> cannedDataBuilder = new Function<String, String>() {
        @Override
        public String apply(String requestUri) {
            //logic to get the canned data based on URI
            return cannedData;
        }
    };

    return new AutoDiscoveryCannedDataResponseCreator(cannedDataBuilder);
}

MockRestServiceServer.createServer(restTemplate)
            .expect(requestContainsUri("/stuff"))
            .andExpect(method(HttpMethod.GET))
            .andRespond(withAutoDetectedCannedData());

它工作得很好!....对于第一个请求。

在第一个请求(/stuff/1.json)之后,我的MockRestServiceServer以消息"Assertion error: no no requests expected“作为响应。

基本上,我可以向该MockRestServiceServer发出与其上的.expect()调用一样多的请求。因为我只有1个请求,所以只有第一个请求会通过。

有没有办法绕过它?我真的不想嘲笑服务C 10或20次…

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2017-01-18 21:01:26

如果你看看MockRestServiceServer类,它支持两个'expect()‘方法。第一个方法缺省为'ExpectedCount.once()‘,但第二个方法允许您更改此值

代码语言:javascript
复制
public ResponseActions expect(RequestMatcher matcher) {
    return this.expect(ExpectedCount.once(), matcher);
}

public ResponseActions expect(ExpectedCount count, RequestMatcher matcher) {
    return this.expectationManager.expectRequest(count, matcher);
}

我找到了这张票据MockRestServiceServer should allow for an expectation to occur multiple times,它概述了第二种方法的一些选项。

在您的例子中,我认为添加静态导入并使用manyTimes()方法比使用for循环更简洁

代码语言:javascript
复制
MockRestServiceServer
            .expect(manyTimes(), requestContainsUri("/stuff"))
            .andExpect(method(HttpMethod.GET))

其他选项包括

代码语言:javascript
复制
once();
manyTimes();
times(5);
min(2);
max(8);
between(3,6);
票数 36
EN

Stack Overflow用户

发布于 2015-12-29 16:01:17

编辑:查看来自@emeraldjava的答案,它为Spring 4.3+用户展示了正确的解决方案。

不幸的是,没有任何很好的机制来期待多个调用。您可以手动执行此操作,也可以使用循环,例如:

代码语言:javascript
复制
for (int i = 0; i < 10; i++) {           
        mockRestServiceServer
                .expect(requestContainsUri("/stuff"))
                .andExpect(method(HttpMethod.GET))
                .andRespond(withAutoDetectedCannedData());
}

请注意,请求必须在没有任何中断的情况下调用,例如,不能有另一个与"/stuff“URI不匹配的REST调用。

票数 12
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/30713734

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档