假设我正在为一个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文件夹中):
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作为字符串,并将模拟数据作为字符串返回!非常出色!
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次…
发布于 2017-01-18 21:01:26
如果你看看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);
}我找到了这张票据MockRestServiceServer should allow for an expectation to occur multiple times,它概述了第二种方法的一些选项。
在您的例子中,我认为添加静态导入并使用manyTimes()方法比使用for循环更简洁
MockRestServiceServer
.expect(manyTimes(), requestContainsUri("/stuff"))
.andExpect(method(HttpMethod.GET))其他选项包括
once();
manyTimes();
times(5);
min(2);
max(8);
between(3,6);发布于 2015-12-29 16:01:17
编辑:查看来自@emeraldjava的答案,它为Spring 4.3+用户展示了正确的解决方案。
不幸的是,没有任何很好的机制来期待多个调用。您可以手动执行此操作,也可以使用循环,例如:
for (int i = 0; i < 10; i++) {
mockRestServiceServer
.expect(requestContainsUri("/stuff"))
.andExpect(method(HttpMethod.GET))
.andRespond(withAutoDetectedCannedData());
}请注意,请求必须在没有任何中断的情况下调用,例如,不能有另一个与"/stuff“URI不匹配的REST调用。
https://stackoverflow.com/questions/30713734
复制相似问题