如何从 ServerResponse 获取 body 作为 String 进行测试?
How to get body as String from ServerResponse for test?
假设我们有一个 o.s.w.reactive.function.server.ServerResponse
.
的实例
获取其正文内容的正确方法是什么,换句话说如何实现 fetchBodyAsString
功能?
test(){
ServerResponse response = getResponseFromService("mock data");
String body = fetchBodyAsString(response);
assertEquals("hello", body);
}
您能否详细说明一下为什么 ServerResponse
对所有内容(cookies(), headers(), statusCode()
)都有方法,但响应主体?我想应该有一种方法可以用 writeTo()
方法获取正文,尽管如何使用它绝对是模糊的。
据我所知,ServerResponse用于控制器或路由器功能。
对于测试,您可以使用 WebTestClient
@Autowired
WebTestClient webTestClient;
@Test
void test() {
webTestClient.get()
.exchange()
.expectStatus()
.isOk()
.expectHeader()
.contentType(MediaType.APPLICATION_JSON)
.expectBody()
.jsonPath("data.name").isEqualTo("name");
}
或
@Autowired
WebTestClient webTestClient;
@Test
void test() {
FluxExchangeResult<String> result = webTestClient.get()
.exchange()
.returnResult(String.class);
int rawStatusCode = result.getRawStatusCode();
HttpStatus status = result.getStatus();
HttpHeaders responseHeaders = result.getResponseHeaders();
String stringResponseBody = result.getResponseBody().blockFirst();
}
出于单元测试的目的,我正在四处寻找类似的东西,并将以下代码拼接在一起。它在 Kotlin 中,但应该相对容易翻译成 Java 并解决您的问题(尽管它确实看起来有点 hacky)。
fun fetchBodyAsString(serverResponse: ServerResponse): String {
val DEFAULT_CONTEXT: ServerResponse.Context = object : ServerResponse.Context {
override fun messageWriters(): List<HttpMessageWriter<*>> {
return HandlerStrategies.withDefaults().messageWriters()
}
override fun viewResolvers(): List<ViewResolver> {
return Collections.emptyList()
}
}
// Only way I could figure out how to get the ServerResponse body was to have it write to an exchange
val request = MockServerHttpRequest.get("http://thisdoenstmatter.com").build()
val exchange = MockServerWebExchange.from(request)
serverResponse.writeTo(exchange, DEFAULT_CONTEXT).block()
val response = exchange.response
return response.bodyAsString.block()!!
}
基本上需要创建一个伪造的 MockServerWebExchange
并让 ServerResponse
写入它以将其转换为 MockServerHttpResponse
,您可以相当轻松地从中提取响应主体。这绝对不优雅,但它确实有效。
另请注意,我没有测试上面的函数本身,只是编译它。它应该可以工作,因为函数的内部代码正是我们正在使用的。
至于你关于ServerResponse
的其他问题,我不知道答案,但也很好奇!
除了 Java 之外,这是基于上面 Alan Yeung 的解决方案。必须有更好的 'native' 方法来做到这一点而不加载应用程序上下文。
public class ServerResponseExtractor {
public static <T> T serverResponseAsObject(ServerResponse serverResponse,
ObjectMapper mapper, Class<T> type) {
String response = serverResponseAsString(serverResponse);
try {
return mapper.readValue(response, type);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
}
public static String serverResponseAsString(ServerResponse serverResponse) {
MockServerWebExchange exchange = MockServerWebExchange.from(
MockServerHttpRequest.get("/foo/foo"));
DebugServerContext debugServerContext = new DebugServerContext();
serverResponse.writeTo(exchange, debugServerContext).block();
MockServerHttpResponse response = exchange.getResponse();
return response.getBodyAsString().block();
}
private static class DebugServerContext implements ServerResponse.Context {
@Override
public List<HttpMessageWriter<?>> messageWriters() {
return HandlerStrategies.withDefaults().messageWriters();
}
@Override
public List<ViewResolver> viewResolvers() {
return Collections.emptyList();
}
}
}
假设我们有一个 o.s.w.reactive.function.server.ServerResponse
.
获取其正文内容的正确方法是什么,换句话说如何实现 fetchBodyAsString
功能?
test(){
ServerResponse response = getResponseFromService("mock data");
String body = fetchBodyAsString(response);
assertEquals("hello", body);
}
您能否详细说明一下为什么 ServerResponse
对所有内容(cookies(), headers(), statusCode()
)都有方法,但响应主体?我想应该有一种方法可以用 writeTo()
方法获取正文,尽管如何使用它绝对是模糊的。
据我所知,ServerResponse用于控制器或路由器功能。 对于测试,您可以使用 WebTestClient
@Autowired
WebTestClient webTestClient;
@Test
void test() {
webTestClient.get()
.exchange()
.expectStatus()
.isOk()
.expectHeader()
.contentType(MediaType.APPLICATION_JSON)
.expectBody()
.jsonPath("data.name").isEqualTo("name");
}
或
@Autowired
WebTestClient webTestClient;
@Test
void test() {
FluxExchangeResult<String> result = webTestClient.get()
.exchange()
.returnResult(String.class);
int rawStatusCode = result.getRawStatusCode();
HttpStatus status = result.getStatus();
HttpHeaders responseHeaders = result.getResponseHeaders();
String stringResponseBody = result.getResponseBody().blockFirst();
}
出于单元测试的目的,我正在四处寻找类似的东西,并将以下代码拼接在一起。它在 Kotlin 中,但应该相对容易翻译成 Java 并解决您的问题(尽管它确实看起来有点 hacky)。
fun fetchBodyAsString(serverResponse: ServerResponse): String {
val DEFAULT_CONTEXT: ServerResponse.Context = object : ServerResponse.Context {
override fun messageWriters(): List<HttpMessageWriter<*>> {
return HandlerStrategies.withDefaults().messageWriters()
}
override fun viewResolvers(): List<ViewResolver> {
return Collections.emptyList()
}
}
// Only way I could figure out how to get the ServerResponse body was to have it write to an exchange
val request = MockServerHttpRequest.get("http://thisdoenstmatter.com").build()
val exchange = MockServerWebExchange.from(request)
serverResponse.writeTo(exchange, DEFAULT_CONTEXT).block()
val response = exchange.response
return response.bodyAsString.block()!!
}
基本上需要创建一个伪造的 MockServerWebExchange
并让 ServerResponse
写入它以将其转换为 MockServerHttpResponse
,您可以相当轻松地从中提取响应主体。这绝对不优雅,但它确实有效。
另请注意,我没有测试上面的函数本身,只是编译它。它应该可以工作,因为函数的内部代码正是我们正在使用的。
至于你关于ServerResponse
的其他问题,我不知道答案,但也很好奇!
除了 Java 之外,这是基于上面 Alan Yeung 的解决方案。必须有更好的 'native' 方法来做到这一点而不加载应用程序上下文。
public class ServerResponseExtractor {
public static <T> T serverResponseAsObject(ServerResponse serverResponse,
ObjectMapper mapper, Class<T> type) {
String response = serverResponseAsString(serverResponse);
try {
return mapper.readValue(response, type);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
}
public static String serverResponseAsString(ServerResponse serverResponse) {
MockServerWebExchange exchange = MockServerWebExchange.from(
MockServerHttpRequest.get("/foo/foo"));
DebugServerContext debugServerContext = new DebugServerContext();
serverResponse.writeTo(exchange, debugServerContext).block();
MockServerHttpResponse response = exchange.getResponse();
return response.getBodyAsString().block();
}
private static class DebugServerContext implements ServerResponse.Context {
@Override
public List<HttpMessageWriter<?>> messageWriters() {
return HandlerStrategies.withDefaults().messageWriters();
}
@Override
public List<ViewResolver> viewResolvers() {
return Collections.emptyList();
}
}
}