'Global exception handling in spring webflux during tests
I'm developing a service with spring webflux. I implemented exception handling using @ControllerAdvice
. It works pretty well, but when I run integration tests it seems that @ControllerAdvice
annotated component is not loaded, resulting in this response:
{
"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
}
This is my controller advice:
@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);
}
}
And this is my integration test 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);
}
}
Solution 1:[1]
if you read the documentation for @WebFluxTest
it states:
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.
This means that
@ContextConfiguration(classes = {MyController.class, MyServiceImpl.class, ExceptionHandlerController.class })
is not what u use here. The @WebFluxTest
annotation does not load @Component
, @Service
or @Repository
It is mainly used to test RestControllers only, and their advices.
The options you have seem to be:
- loading MyController.class and then mock any dependency this class has (MyServiceImpl.class)
- load a full Context using
@SpringBootTest
instead combined with@AutoConfigureWebTestClient
Solution 2:[2]
Just a not on top of the already accepted answer which is totally correct. The usage of @ContextConfiguration is necessary only for testing Functional endpoints. I Think this is probably what confuses people.
@WebFluxTest is used during functional endpoint tests for starting the web context and server. But since we dont use controllers, we have to use @ContextConfiguration to bring the handler and routerFunction beans in our spring context.
In this case since we use annotated controller a simple @WebFluxTest(Controller.class) is more than enough for unit testing.
Solution 3:[3]
Adding controllerAdvice in the WebTestClient solved the issue.
WebTestClient.bindToController(controller)
.controllerAdvice(errorControllerAdvice)
.build()
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Toerktumlare |
Solution 2 | homeOfTheWizard |
Solution 3 | SANN3 |