测试期间 spring webflux 中的全局异常处理
Global exception handling in spring webflux during tests
我正在使用 spring webflux 开发一项服务。我使用 @ControllerAdvice
实现了异常处理。它工作得很好,但是当我 运行 集成测试时,似乎 @ControllerAdvice
注释组件没有加载,导致这个响应:
{
"timestamp":"2019-11-28T08:56:47.285+0000",
"path":"/fooController/bar",
"status":500,
"error":"Internal Server Error",
"message":"java.lang.IllegalStateException: Could not resolve parameter [1] in protected org.springframework.http.ResponseEntity<it.test.model.Response> it.test.exception.ExceptionHandlerController.handleServiceException(java.lang.Exception,org.springframework.web.context.request.WebRequest): No suitable resolver
}
这是我的控制器建议:
@ControllerAdvice
public class ExceptionHandlerController extends ResponseEntityExceptionHandler {
private final Logger logger = LoggerFactory.getLogger(ExceptionHandlerController.class);
@ExceptionHandler
protected ResponseEntity<Response> handleServiceException(Exception ex, WebRequest request) {
this.logger.error("Error occurred: \"{}\"", ex.getMessage());
Response<Foo> response = new Response<>(new Foo(),
"generic error",
HttpStatus.INTERNAL_SERVER_ERROR);
return new ResponseEntity<>(response, null, HttpStatus.OK);
}
}
这是我的集成测试class
@ExtendWith(SpringExtension.class)
@WebFluxTest(MyController.class)
@ContextConfiguration(classes = {MyController.class, MyServiceImpl.class, ExceptionHandlerController.class })
public class MyControllerIT {
@Autowired
private WebTestClient webTestClient;
@Test
public void testShouldFail() throws IOException {
return this.webTestClient.get()
.uri(uri)
.accept(MediaType.APPLICATION_JSON)
.exchange()
.expectStatus().isOk()
.expectBody()
.jsonPath("$.statusCode").isEqualTo(500);
}
}
如果您阅读 @WebFluxTest
的 documentation,它指出:
Annotation that can be used for a Spring WebFlux test that focuses
only on Spring WebFlux components.
Using this annotation will disable full auto-configuration and instead
apply only configuration
relevant to WebFlux tests (i.e. @Controller, @ControllerAdvice,
@JsonComponent, Converter/GenericConverter, and WebFluxConfigurer
beans but not @Component, @Service or @Repository beans).
Typically @WebFluxTest is used in combination with @MockBean or
@Import to create any collaborators required by your @Controller
beans.
If you are looking to load your full application configuration and use
WebTestClient, you should consider @SpringBootTest combined with
@AutoConfigureWebTestClient rather than this annotation.
这意味着
@ContextConfiguration(classes = {MyController.class, MyServiceImpl.class, ExceptionHandlerController.class })
是不是你在这里使用的。 @WebFluxTest
注释不加载 @Component
、@Service
或 @Repository
主要用于测试RestControllers,以及他们的建议。
您的选项似乎是:
- 加载 MyController.class 然后模拟此 class 具有的任何依赖项 (MyServiceImpl.class)
- 使用
@SpringBootTest
加载完整上下文,而不是结合
@AutoConfigureWebTestClient
只是不在已经接受的答案之上,这是完全正确的。
只有在测试功能端点时才需要使用 @ContextConfiguration。我想这可能是人们困惑的地方。
@WebFluxTest 在功能端点测试期间用于启动 Web 上下文和服务器。
但是由于我们不使用控制器,我们必须使用@ContextConfiguration 将处理程序和 routerFunction bean 引入我们的 spring 上下文中。
在这种情况下,因为我们使用带注释的控制器,所以一个简单的@WebFluxTest(Controller.class) 就足以进行单元测试了。
在 WebTestClient 中添加 controllerAdvice 解决了问题。
WebTestClient.bindToController(controller)
.controllerAdvice(errorControllerAdvice)
.build()
我正在使用 spring webflux 开发一项服务。我使用 @ControllerAdvice
实现了异常处理。它工作得很好,但是当我 运行 集成测试时,似乎 @ControllerAdvice
注释组件没有加载,导致这个响应:
{
"timestamp":"2019-11-28T08:56:47.285+0000",
"path":"/fooController/bar",
"status":500,
"error":"Internal Server Error",
"message":"java.lang.IllegalStateException: Could not resolve parameter [1] in protected org.springframework.http.ResponseEntity<it.test.model.Response> it.test.exception.ExceptionHandlerController.handleServiceException(java.lang.Exception,org.springframework.web.context.request.WebRequest): No suitable resolver
}
这是我的控制器建议:
@ControllerAdvice
public class ExceptionHandlerController extends ResponseEntityExceptionHandler {
private final Logger logger = LoggerFactory.getLogger(ExceptionHandlerController.class);
@ExceptionHandler
protected ResponseEntity<Response> handleServiceException(Exception ex, WebRequest request) {
this.logger.error("Error occurred: \"{}\"", ex.getMessage());
Response<Foo> response = new Response<>(new Foo(),
"generic error",
HttpStatus.INTERNAL_SERVER_ERROR);
return new ResponseEntity<>(response, null, HttpStatus.OK);
}
}
这是我的集成测试class
@ExtendWith(SpringExtension.class)
@WebFluxTest(MyController.class)
@ContextConfiguration(classes = {MyController.class, MyServiceImpl.class, ExceptionHandlerController.class })
public class MyControllerIT {
@Autowired
private WebTestClient webTestClient;
@Test
public void testShouldFail() throws IOException {
return this.webTestClient.get()
.uri(uri)
.accept(MediaType.APPLICATION_JSON)
.exchange()
.expectStatus().isOk()
.expectBody()
.jsonPath("$.statusCode").isEqualTo(500);
}
}
如果您阅读 @WebFluxTest
的 documentation,它指出:
Annotation that can be used for a Spring WebFlux test that focuses only on Spring WebFlux components.
Using this annotation will disable full auto-configuration and instead apply only configuration relevant to WebFlux tests (i.e. @Controller, @ControllerAdvice, @JsonComponent, Converter/GenericConverter, and WebFluxConfigurer beans but not @Component, @Service or @Repository beans).
Typically @WebFluxTest is used in combination with @MockBean or @Import to create any collaborators required by your @Controller beans.
If you are looking to load your full application configuration and use WebTestClient, you should consider @SpringBootTest combined with @AutoConfigureWebTestClient rather than this annotation.
这意味着
@ContextConfiguration(classes = {MyController.class, MyServiceImpl.class, ExceptionHandlerController.class })
是不是你在这里使用的。 @WebFluxTest
注释不加载 @Component
、@Service
或 @Repository
主要用于测试RestControllers,以及他们的建议。
您的选项似乎是:
- 加载 MyController.class 然后模拟此 class 具有的任何依赖项 (MyServiceImpl.class)
- 使用
@SpringBootTest
加载完整上下文,而不是结合@AutoConfigureWebTestClient
只是不在已经接受的答案之上,这是完全正确的。 只有在测试功能端点时才需要使用 @ContextConfiguration。我想这可能是人们困惑的地方。
@WebFluxTest 在功能端点测试期间用于启动 Web 上下文和服务器。 但是由于我们不使用控制器,我们必须使用@ContextConfiguration 将处理程序和 routerFunction bean 引入我们的 spring 上下文中。
在这种情况下,因为我们使用带注释的控制器,所以一个简单的@WebFluxTest(Controller.class) 就足以进行单元测试了。
在 WebTestClient 中添加 controllerAdvice 解决了问题。
WebTestClient.bindToController(controller)
.controllerAdvice(errorControllerAdvice)
.build()