- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在研究 Spring WebFlux 项目,
我正在调用第三方 API 使用 WebClient 创建实体。
如果 WebClient 获取 4xx 作为响应代码,我想保留错误。
下面是请求第三方API的代码
API.java
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.web.reactive.function.client.ClientResponse;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;
class API {
public Mono<Response> create(Request req) {
return WebClient.builder()
.baseUrl("http://localhost:8080")
.defaultHeader(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE)
.build()
.post()
.uri("/v1/student")
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON)
.bodyValue(req.getData())
.retrieve()
.onStatus(HttpStatus::is4xxClientError, response -> handleError(response))
.bodyToMono(Response.class);
}
private Mono<? extends ClientException> handleError(ClientResponse response) {
return response
.bodyToMono(ErrorResponse.class)
.map(errorResponse -> new ClientException(errorResponse));
}
}
如果服务器返回 4xx 响应,那么我只是将其转换为特定的错误响应。
调用方法如下
APIService.java
public class APIService {
API api;
private ResponseHandler responseHandler;
ErrorProcessor errorProcessor;
public APIService(API api, ResponseHandler responseHandler, ErrorProcessor errorProcessor) {
this.api = api;
this.responseHandler = responseHandler;
this.errorProcessor = errorProcessor;
}
public void process(Request request) {
api.create(request)
.doOnSuccess(response -> responseHandler.process(response))
.doOnError(
throwable -> {
ClientException ce = (ClientException) throwable;
errorProcessor.process(ce);
})
.block();
}
}
Request.java
public class Request {
final Map<String, Integer> data;
public Request(int id) {
data = new HashMap<>();
data.put("counter", id);
}
public Map<String, Integer> getData() {
return data;
}
}
Response.java
public class Response {
int id;
public Response(int id) {
this.id = id;
}
}
ResponseHandler.java
import java.util.logging.Logger;
public class ResponseHandler {
Logger log = Logger.getLogger(ResponseHandler.class.getName());
public void process(Response response) {
log.info("Id=" + response.id);
}
}
异常处理类
ClientException.java
public class ClientException extends RuntimeException {
private ErrorResponse errorResponse;
public ClientException(ErrorResponse errorResponse) {
this.errorResponse = errorResponse;
}
public ErrorResponse getErrorResponse() {
return errorResponse;
}
}
错误处理器
ErrorProcessor.java
import java.util.logging.Logger;
public class ErrorProcessor {
Logger log = Logger.getLogger(ErrorProcessor.class.getName());
public void process(ClientException ce) {
log.info(ce.getErrorResponse().getErrorCode() + "=" + ce.getErrorResponse().getMessage());
}
}
API调用返回的错误响应
ErrorResponse.java
public class ErrorResponse {
String errorCode;
String message;
public ErrorResponse(String errorCode, String message) {
this.errorCode = errorCode;
this.message = message;
}
public String getErrorCode() {
return errorCode;
}
public String getMessage() {
return message;
}
}
编写Junit时如下
APITest.java
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
import reactor.core.publisher.Mono;
@ExtendWith(MockitoExtension.class)
public class APITest {
@Mock API api;
@Mock ErrorProcessor errorProcessor;
@Mock ResponseHandler responseHandler;
@InjectMocks APIService apiService;
@Test
public void givenRequest_shouldCreate() {
// given
Request request = new Request(1);
Mockito.when(api.create(request)).thenReturn(Mono.just(new Response(1)));
// when
apiService.process(request);
// then
Mockito.verify(api, Mockito.times(1)).create(request);
Mockito.verify(responseHandler,Mockito.times(1)).process(Mockito.any(Response.class));
}
//Failing Test
@Test
public void givenRequest_shouldThrow() {
// given
Request request = new Request(1);
Mockito.when(api.create(request))
.thenReturn(
Mono.error(new ClientException(new ErrorResponse("0101", "This is failed request"))));
// when
apiService.process(request);
// then
Mockito.verify(errorProcessor, Mockito.times(1)).process(Mockito.any(ClientException.class));
}
}
我的测试方法givenRequest_shouldCreate正在验证一旦API响应到来,我的ResponseHandler就会被调用。
但是以同样的方式进入测试方法givenRequest_shouldThrow,我想验证一下,如果发生任何错误,那么我的 ErrorProcessor 就会被调用
当我运行上述测试时,出现以下错误
com.service.ClientException
at com.service.APITest.givenRequest_shouldThrow(APITest.java:37)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:675)
at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:125)
at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:132)
at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:124)
at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:74)
at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(ExecutableInvoker.java:115)
at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:104)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:62)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:43)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:35)
at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104)
at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$6(TestMethodTestDescriptor.java:202)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:198)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:135)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:69)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:135)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
at java.util.ArrayList.forEach(ArrayList.java:1257)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
at java.util.ArrayList.forEach(ArrayList.java:1257)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:32)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:51)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:229)
at org.junit.platform.launcher.core.DefaultLauncher.lambda$execute$6(DefaultLauncher.java:197)
at org.junit.platform.launcher.core.DefaultLauncher.withInterceptedStreams(DefaultLauncher.java:211)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:191)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:128)
at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:69)
at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:230)
at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:58)
Suppressed: java.lang.Exception: #block terminated with an error
at reactor.core.publisher.BlockingSingleSubscriber.blockingGet(BlockingSingleSubscriber.java:93)
at reactor.core.publisher.Mono.block(Mono.java:1663)
at com.service.APIService.process(APIService.java:25)
at com.service.APITest.givenRequest_shouldThrow(APITest.java:41)
... 63 more
所以我想要模拟的是,当我调用 create 方法时,它将返回 Mono.error 所以在 .doOnError 中我想保留错误。所以我想确保我的 errorHandler.saveError 方法是否被调用。
有人可以帮我解决这个问题吗
谢谢
阿尔佩什
最佳答案
您的测试应该期望 process
方法抛出异常,请参见下面的示例。 this thread 中列出了更多奇特的异常断言方法。 .
//Failing Test
@Test
public void givenRequest_shouldThrow() {
// given
Request request = new Request(1);
Mockito.when(api.create(request))
.thenReturn(
Mono.error(new ClientException(new ErrorResponse("0101", "This is failed request"))));
// when
try {
apiService.process(request);
fail("Process should have thrown an exception");
} catch (ClientException e) {
// then
assertEquals("0101", e.getErrorResponse().errorCode);
assertEquals("This is failed request", e.getErrorResponse().message);
assertNull(e.getMessage());
Mockito.verify(errorProcessor, Mockito.times(1)).process(Mockito.any(ClientException.class));
}
}
关于java - Spring Webflux 如何将 WebClient Junit 的响应模拟为 Mono.error,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59954336/
我希望缓存Mono(仅在成功的情况下),这是WebClient调用的结果。 通过阅读项目 react 堆插件文档,我觉得CacheMono不太适合,因为它也存储了我不想要的错误。 因此,我没有使用Ca
我用 webflux 与 网易和 jdbc ,所以我以下一种方式包装阻塞 jdbc 操作: static Mono fromOne(Callable blockingOperation) {
有人可以告诉我或使用 提供现成的 CRUD 示例吗? WebFlux、RScoket 和 Spring(或 SpringBoot) ? 我研究了 RSocket 文档, WebFlux ,也写了我的简
我正在通过代理连接使用ssl服务测试webclient,但是使用安全ssl连接时出现以下错误。 你知道是什么问题吗? 堆栈跟踪: {"timestamp":"2019-10-29T18:35:43.5
public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { Flux body = exchange.
我创建了一个过滤器,我可以在其中访问有效负载的主体并对其执行一些逻辑(现在假设我记录主体)。在最后一步中,我返回了 Mono,但是当请求通过 Controller 继续发送到服务时,它会抛出请求正文丢
上次我在考虑在我们的应用程序中正确使用记录器。例如,我有一个返回用户流的 Controller ,但在日志中,我看到“获取用户”日志正在被另一个线程而不是处理管道上的线程记录,但这是一个好方法吗? @
我正在使用带有 Netty 的 Spring Webflux (2.0.3.RELEASE) 并尝试了解服务器和 Web 客户端如何使用线程。我用 WebClient 编写了一些带有 http 调用链
我面临一个问题。我正在使用 Spring Webflux 并行调用一些 API。如果任何子线程面临任何问题,它需要记录请求。现在的问题是,用于记录一个普通的 POJO 类,其中有一个静态方法通过 Ap
我试图用 JSP 配置 Spring WebFlux。我在 Spring WebFlux 中没有看到任何支持 JSTL View 的 View 类。这是否意味着我们不能使用 Spring WebFlu
我正在寻找一种在响应式(Reactive) API 中使用计划任务的方法。 我知道它使用线程池,所以它与 webflux 组件不太兼容。 你有同等的人来做这项工作吗? 非常感谢 萨维留 最佳答案 有几
我曾经调用 HttpServletRequest.getRemoteAddr() 来获取客户端 ip。 我想知道如何通过 ServerWebExchange 获得它。 我最好的猜测是: serve
我想使用 spring webflux 以 react 方式流式传输文件。 我的端点应该看起来更具体什么是对象的类型? @GetMapping("/file") Flux file() { /
我无法让我的响应式(Reactive)代码以一种常见的方式处理错误。理想的方式是使用可重用的组件,我可以将其作为依赖项添加到其他项目中。 过去,我们使用 @RestControllerAdvise 通
我们正在尝试对 Webflux 使用react。我们将 Jaegar 与 Istio 用于检测目的。 Jaegar 非常了解 Spring MVC 端点,但似乎对 WebFlux 根本不起作用。 我正
我是响应式(Reactive)编程和 Spring WebFlux 的新手。我想让我的 App 1 通过 Flux 发布 Server Sent 事件,我的 App 2 持续监听它。 我希望 Flux
我正在我的项目中尝试新的 ReactiveQuerydslPredicateExecutor 但我找不到 findAll(Predicate, Pageable) 的方法,就像我在 QueryDslP
我正在使用 Spring WebFlux webclient 进行 REST 调用。我已经在 3000 上配置了连接超时毫秒,相应地: WebClient webClient = WebClient.
我想测量使用 WebFlux 进行的一些异步调用的长度。我一直在阅读各种来源,据我所知,@Timed 注释与 AspectJ 一起工作,基本上只是在方法调用之前启动一个计时器,然后停止它。这显然不适用
我有一个 Reactor Kafka 应用程序,它无限期地使用来自主题的消息。我需要公开一个健康检查 REST 端点,它可以指示此过程的健康状况——主要是想知道 Kafka 接收器通量序列是否已终止,
我是一名优秀的程序员,十分优秀!