1

I have provided a configuration class to my Declarative HttpClient, to force throwing an exception on error (status>400), or maybe I misunderstood the exceptionOnErrorStatus configuration option.

@Client(value = "/", configuration = ApiClientConfiguration)
interface Api {
    @Get("/author/{id}")
    AuthorResource getAuthor(Long id, @Header(name="Authorization") String authorization)
}

Here's the configuration class

@ConfigurationProperties("httpclient.api")
class ApiClientConfiguration extends DefaultHttpClientConfiguration {
    @Override
    boolean isExceptionOnErrorStatus() {
        return true
    }
}

My @MicronautTest is expected to throw an exception, but it doesn't:

    def "It fails to get an non-existing Author"() {
        given:
        def token = viewer()

        when:
        //This commented code throws an exception as expected
/*
        def author = client.toBlocking().exchange(HttpRequest.create(
                HttpMethod.GET,
                "/author/${badId}"
        ).bearerAuth(token))
*/
        //This does not despite the provided HttpClientConfiguration
        def author = api.getAuthor(badId, bearerAuth(token))

        then:
        def ex = thrown(HttpClientResponseException)
        ex.status == NOT_FOUND
        ex.getResponse().getBody(ErrorResource).map {
            assert it.message == "Author with id ${badId} not found."
            it
        }.isPresent()

        where:
        badId = anyInt()
    }

Any help appreciated. I am not used to configuration classes, so there may be a mistake in how I use it, the other possibility is that exceptionOnErrorStatus does not mean what I think it means. I have checked the documentation and I think it does, though.

Luis Muñiz
  • 4,649
  • 1
  • 27
  • 43
  • I think it's relevant to note that I'm using the Netty server, as after running the tests in a debugger, the only place where my `isExceptionOnErrorStatus()` is called during the exwecution, is when checking if the body type should be converted. So my COnfiguration class is properly used and the property is properly reported, but the code just does not do what the propery is promising... – Luis Muñiz Nov 06 '22 at 19:53

1 Answers1

0

It looks like the Configuration class is used, the method isExceptionOnErrorStatus() is called, but it is not interpreted as I thought it would.

Conclusion, when you are using a Declarative client and want to test the response when the status>400, make your interface return a HttpResponse<X>.

    @Get("/author/{id}")
    HttpResponse<AuthorResource> getAuthor(Long id, @Header(name = "Authorization") String authorization)

The behaviour is different from the low-level client, which throws an exception.

Modify your Test:

        def response = api.getAuthor(badId, bearerAuth(token))
        response.status == NOT_FOUND
        response.getBody(ErrorResponse).map {
            assert it.message == "Author with id ${badId} not found."
            it
        }.isPresent()
Luis Muñiz
  • 4,649
  • 1
  • 27
  • 43