Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/spring-mvc/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/cocoa/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Spring MockRestServiceServer处理对同一URI的多个请求(自动发现)_Spring_Spring Mvc_Mocking_Integration Testing - Fatal编程技术网

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

Spring MockRestServiceServer处理对同一URI的多个请求(自动发现),spring,spring-mvc,mocking,integration-testing,Spring,Spring Mvc,Mocking,Integration Testing,假设我正在为一个REST服务a编写Spring集成测试。该服务依次命中另一个REST服务B,并获取一个要命中REST服务C的URI列表。这是一种自动发现模式。我想使用MockRestServiceServer模拟B和C响应。 现在来自B的响应是一个URI列表,它们都非常相似,为了示例起见,让我们假设我来自B的响应如下: { uris: ["/stuff/1.json", "/stuff/2.json", "/stuff/39.json", "/stuff/47.json"] } 简单地

假设我正在为一个REST服务a编写Spring集成测试。该服务依次命中另一个REST服务B,并获取一个要命中REST服务C的URI列表。这是一种自动发现模式。我想使用MockRestServiceServer模拟B和C响应。
现在来自B的响应是一个URI列表,它们都非常相似,为了示例起见,让我们假设我来自B的响应如下:

{
    uris: ["/stuff/1.json", "/stuff/2.json", "/stuff/39.json", "/stuff/47.json"]
}
简单地说,服务A会将它们中的每一个附加到服务C的基本URL上,并发出这些请求。
模拟B很容易,因为它只是一个请求。
模拟C是一件麻烦事,因为我必须模拟每个URI以获得适当的模拟响应。我想把它自动化
因此,首先我编写了自己的匹配器,以匹配的不是完整的URL,而是其中的一部分:

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));
    }
}
这很好,因为现在我可以做到:

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文件夹中):

公共类自动发现CanneddataResponseCreator实现ResponseCreator{
私有最终函数cannedDataBuilder;
公共自动发现CannedDataResponseSecretor(函数cannedDataBuilder){
this.cannedDataBuilder=cannedDataBuilder;
}
@凌驾
公共ClientHttpResponse createResponse(ClientHttpRequest ClientHttpRequest)抛出IOException{
使用success返回(cannedDataBuilder.apply(requestUri),MediaType.APPLICATION\u JSON)
.createResponse(clientHttpRequest);
}
}
现在事情很简单了,我必须编写一个生成器,将请求URI作为字符串,并以字符串的形式返回模拟数据!太棒了

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());
public ResponseCreator with autodetectedcanneddata(){
函数cannedDataBuilder=新函数(){
@凌驾
公共字符串应用(字符串请求URI){
//基于URI获取屏蔽数据的逻辑
返回罐头数据;
}
};
返回新的AutoDiscoveryCannedDataResponseSecretor(cannedDataBuilder);
}
MockRestServiceServer.createServer(restTemplate)
.expect(requestContainsUri(“/stuff”))
.andExpect(方法(HttpMethod.GET))
.andRespond(使用自动检测的CannedData());
它很好用。。。。对于第一个请求。
在第一个请求(/stuff/1.json)之后,我的MockRestServiceServer响应消息“断言错误:不需要进一步的请求”。
基本上,我可以向该MockRestServiceServer发出与对其进行.expect()调用一样多的请求。因为我只有一个,所以只有第一个请求会通过。

有办法绕过它吗?我真的不想模拟服务C 10或20次…

编辑:请参阅@emeraldjava的答案,它为Spring 4.3+用户提供了正确的解决方案

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

for (int i = 0; i < 10; i++) {           
        mockRestServiceServer
                .expect(requestContainsUri("/stuff"))
                .andExpect(method(HttpMethod.GET))
                .andRespond(withAutoDetectedCannedData());
}
for(inti=0;i<10;i++){
mockRestServiceServer
.expect(requestContainsUri(“/stuff”))
.andExpect(方法(HttpMethod.GET))
.andRespond(使用自动检测的CannedData());
}

请注意,必须在不中断的情况下调用请求,例如,不能有与“/stuff”URI不匹配的其他REST调用。

如果查看MockRestServiceServer类,它支持两个“expect()”方法。第一个方法默认为“ExpectedCount.once()”,但第二个方法允许您更改此值

public ResponseActions expect(RequestMatcher matcher) {
    return this.expect(ExpectedCount.once(), matcher);
}

public ResponseActions expect(ExpectedCount count, RequestMatcher matcher) {
    return this.expectationManager.expectRequest(count, matcher);
}
我找到了这张票,上面列出了第二种方法的一些选择

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

MockRestServiceServer
            .expect(manyTimes(), requestContainsUri("/stuff"))
            .andExpect(method(HttpMethod.GET))
其他选择包括

once();
manyTimes();
times(5);
min(2);
max(8);
between(3,6);

感谢RequestContaineSuriMatcher的实现一旦测试了预期,就不能添加额外的预期<代码>无法添加更多预期的请求,测试已在进行中在Spring 4.3中实现。这是正确的答案,应按此选择。
once();
manyTimes();
times(5);
min(2);
max(8);
between(3,6);