WebTestClient always return status 500 on exception test case Spring WebFlux

82 Views Asked by At

Im struggling with testing controller of WebFlux app. Test always returns 500 even though I mock status 404. I read that adding onErrorResume solves this problem because otherwise error is handled in AbstractErrorWebExceptionHandler but this doesn't solve my problem. Endpoints work fine when working working with them in swagger.

Service code

        return githubWebClient.get()
                .uri(("/users/{username}/repos"), username)
                .retrieve()
                .onStatus(httpStatusCode -> httpStatusCode.value() == 404,
                        error -> Mono.error(new GithubUserNotFoundException("Github api did not find user: " + username)))
                .bodyToFlux(Repository.class)
                .onErrorMap(Throwable.class, throwable -> new Exception("plain exception"))
                .flatMap(this::fetchBranchesForRepository)
                .filter(repository -> !repository.fork());
    }

Controller advice code

@RestControllerAdvice
public class RestControllerHandler {

    @ExceptionHandler(GithubUserNotFoundException.class)
    @ResponseStatus(HttpStatus.NOT_FOUND)
    public ExceptionMessage handleGithubUserNotFoundException(GithubUserNotFoundException ex){
        ExceptionMessage exceptionMessage = ExceptionMessage
                .builder()
                .message(ex.getMessage())
                .status(404)
                .build();
        log.error("Exception has been occurred", ex);
        return exceptionMessage;
    }

Test code

    @Test
    void shouldThrowException_WhenApiCantFindUser() {
        String user = "test";

        WireMock.stubFor(WireMock.get(WireMock.urlEqualTo("/users/" + user + "/repos"))
                .willReturn(WireMock.notFound()));

        webTestClient.get()
                .uri(user)
                .exchange()
                .expectStatus()
                .isNotFound();
    }

Console logs

2024-02-16T11:34:38.652+01:00  INFO 92904 --- [     parallel-1] pl.hubert.task.client.GithubClient       : Fetching repositories for user: test
2024-02-16T11:34:38.749+01:00 ERROR 92904 --- [     parallel-1] i.n.r.d.DnsServerAddressStreamProviders  : Unable to load io.netty.resolver.dns.macos.MacOSDnsServerAddressStreamProvider, fallback to system defaults. This may result in incorrect DNS resolutions on MacOS. Check whether you have a dependency on 'io.netty:netty-resolver-dns-native-macos'. Use DEBUG level to see the full stack: java.lang.UnsatisfiedLinkError: failed to load the required native library
2024-02-16T11:34:38.888+01:00 ERROR 92904 --- [ctor-http-nio-3] o.s.w.s.adapter.HttpWebHandlerAdapter    : [63e1e91b] 500 Server Error for HTTP GET "/api/github/test"

java.lang.Exception: plain exception
    at pl.hubert.task.client.GithubClient.lambda$getUserRepositories$2(GithubClient.java:33) ~[main/:na]
    Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException: 
Error has been observed at the following site(s):
    *__checkpoint ⇢ Handler pl.hubert.task.controller.GithubController#getGithubReposByUsername(String) [DispatcherHandler]
    *__checkpoint ⇢ HTTP GET "/api/github/test" [ExceptionHandlingWebHandler]
Original Stack Trace:
        at pl.hubert.task.client.GithubClient.lambda$getUserRepositories$2(GithubClient.java:33) ~[main/:na]
        at reactor.core.publisher.Flux.lambda$onErrorMap$28(Flux.java:7239) ~[reactor-core-3.6.2.jar:3.6.2]
        at reactor.core.publisher.Flux.lambda$onErrorResume$29(Flux.java:7292) ~[reactor-core-3.6.2.jar:3.6.2]
        at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onError(FluxOnErrorResume.java:94) ~[reactor-core-3.6.2.jar:3.6.2]
        at reactor.core.publisher.MonoFlatMapMany$FlatMapManyInner.onError(MonoFlatMapMany.java:256) ~[reactor-core-3.6.2.jar:3.6.2]
        at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.onError(Operators.java:2236) ~[reactor-core-3.6.2.jar:3.6.2]
        at reactor.core.publisher.MonoFlatMap$FlatMapMain.onError(MonoFlatMap.java:180) ~[reactor-core-3.6.2.jar:3.6.2]
        at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onError(FluxOnErrorResume.java:106) ~[reactor-core-3.6.2.jar:3.6.2]
        at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.onError(MonoIgnoreThen.java:280) ~[reactor-core-3.6.2.jar:3.6.2]
        at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.subscribeNext(MonoIgnoreThen.java:232) ~[reactor-core-3.6.2.jar:3.6.2]
        at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.onComplete(MonoIgnoreThen.java:204) ~[reactor-core-3.6.2.jar:3.6.2]
        at reactor.core.publisher.FluxOnErrorReturn$ReturnSubscriber.onComplete(FluxOnErrorReturn.java:169) ~[reactor-core-3.6.2.jar:3.6.2]
        at reactor.core.publisher.MonoIgnoreElements$IgnoreElementsSubscriber.onComplete(MonoIgnoreElements.java:89) ~[reactor-core-3.6.2.jar:3.6.2]
        at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onComplete(FluxMapFuseable.java:152) ~[reactor-core-3.6.2.jar:3.6.2]
        at reactor.core.publisher.FluxMap$MapSubscriber.onComplete(FluxMap.java:144) ~[reactor-core-3.6.2.jar:3.6.2]
        at reactor.core.publisher.FluxPeek$PeekSubscriber.onComplete(FluxPeek.java:260) ~[reactor-core-3.6.2.jar:3.6.2]
        at reactor.core.publisher.FluxMap$MapSubscriber.onComplete(FluxMap.java:144) ~[reactor-core-3.6.2.jar:3.6.2]
        at reactor.netty.channel.FluxReceive.onInboundComplete(FluxReceive.java:415) ~[reactor-netty-core-1.1.15.jar:1.1.15]
        at reactor.netty.channel.ChannelOperations.onInboundComplete(ChannelOperations.java:446) ~[reactor-netty-core-1.1.15.jar:1.1.15]
        at reactor.netty.channel.ChannelOperations.terminate(ChannelOperations.java:500) ~[reactor-netty-core-1.1.15.jar:1.1.15]
        at reactor.netty.http.client.HttpClientOperations.onInboundNext(HttpClientOperations.java:782) ~[reactor-netty-http-1.1.15.jar:1.1.15]
        at reactor.netty.channel.ChannelOperationsHandler.channelRead(ChannelOperationsHandler.java:114) ~[reactor-netty-core-1.1.15.jar:1.1.15]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:444) ~[netty-transport-4.1.105.Final.jar:4.1.105.Final]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420) ~[netty-transport-4.1.105.Final.jar:4.1.105.Final]
        at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412) ~[netty-transport-4.1.105.Final.jar:4.1.105.Final]
        at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:103) ~[netty-codec-4.1.105.Final.jar:4.1.105.Final]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:444) ~[netty-transport-4.1.105.Final.jar:4.1.105.Final]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420) ~[netty-transport-4.1.105.Final.jar:4.1.105.Final]
        at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412) ~[netty-transport-4.1.105.Final.jar:4.1.105.Final]
        at io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelRead(CombinedChannelDuplexHandler.java:436) ~[netty-transport-4.1.105.Final.jar:4.1.105.Final]
        at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:346) ~[netty-codec-4.1.105.Final.jar:4.1.105.Final]
        at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:318) ~[netty-codec-4.1.105.Final.jar:4.1.105.Final]
        at io.netty.channel.CombinedChannelDuplexHandler.channelRead(CombinedChannelDuplexHandler.java:251) ~[netty-transport-4.1.105.Final.jar:4.1.105.Final]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:442) ~[netty-transport-4.1.105.Final.jar:4.1.105.Final]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420) ~[netty-transport-4.1.105.Final.jar:4.1.105.Final]
        at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412) ~[netty-transport-4.1.105.Final.jar:4.1.105.Final]
        at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410) ~[netty-transport-4.1.105.Final.jar:4.1.105.Final]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:440) ~[netty-transport-4.1.105.Final.jar:4.1.105.Final]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420) ~[netty-transport-4.1.105.Final.jar:4.1.105.Final]
        at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919) ~[netty-transport-4.1.105.Final.jar:4.1.105.Final]
        at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:166) ~[netty-transport-4.1.105.Final.jar:4.1.105.Final]
        at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:788) ~[netty-transport-4.1.105.Final.jar:4.1.105.Final]
        at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:724) ~[netty-transport-4.1.105.Final.jar:4.1.105.Final]
        at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:650) ~[netty-transport-4.1.105.Final.jar:4.1.105.Final]
        at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:562) ~[netty-transport-4.1.105.Final.jar:4.1.105.Final]
        at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:997) ~[netty-common-4.1.105.Final.jar:4.1.105.Final]
        at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) ~[netty-common-4.1.105.Final.jar:4.1.105.Final]
        at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) ~[netty-common-4.1.105.Final.jar:4.1.105.Final]
        at java.base/java.lang.Thread.run(Thread.java:1583) ~[na:na]

2024-02-16T11:34:38.910+01:00 ERROR 92904 --- [    Test worker] o.s.t.w.reactive.server.ExchangeResult   : Request details for assertion failure:

> GET /api/github/test
> WebTestClient-Request-Id: [1]

No content

< 500 INTERNAL_SERVER_ERROR Internal Server Error
< 

0 bytes of content (unknown content-type).


Status expected:<404 NOT_FOUND> but was:<500 INTERNAL_SERVER_ERROR>
Expected :404 NOT_FOUND
Actual   :500 INTERNAL_SERVER_ERROR
<Click to see difference>

java.lang.AssertionError: Status expected:<404 NOT_FOUND> but was:<500 INTERNAL_SERVER_ERROR>
0

There are 0 best solutions below