Affects: Spring Boot 2.6.3 and below


During one of my integration tests, to test one endpoint I encountered the following error:

org.springframework.web.reactive.function.client.WebClientRequestException: Connection refused

I'm using the webflux starter version 2.6.3, but the problem I'm describing is reproducible with lower version.

These are the annotations applied to my test:

@SpringBootTest(webEnvironment = RANDOM_PORT)
@ActiveProfiles("test")
@Sql("classpath:sql/my_sql.sql")
@Import(TestConfig.class)

and this is the code is raising the issue:

        URI uri = UriComponentsBuilder
                .fromUriString(MY_URL)
                .queryParam("year", 2005)
                .buildAndExpand()
                .toUri();

        client.get()
                .uri(uri)
                .exchange()
                .expectStatus()
                .is2xxSuccessful();

After analyzing the problem, I found out that the issue is caused by the use of @SpringBootTest(webEnvironment = RANDOM_PORT) without @AutoConfigureWebTestClient (this should be possible since @SpringBootTest registers a WebTestClient) and the use of the S uri(URI uri); implementation in the UriSpec interface inside the WebTestClient interface.

In other words by rewriting the test as:

        URI uri = UriComponentsBuilder
                .fromUriString(MY_URL)
                .queryParam("year", 2005)
                .buildAndExpand()
                .toUri();

        client.get()
                .uri(uri.toString) // Using another method to specify the URI
                .exchange()
                .expectStatus()
                .is2xxSuccessful();

The DefaultWebTestClient is injected with a uriBuilderFactory (DefaultUriBuilderFactory) where its field private final UriComponentsBuilder baseUri; is not null.

In the first case the URI returned is missing the base URI (http//host:port/ -- for example, /myUrl?year=2005), whilst in the second case the URI returned contains the base URI (http//host:port/myUrl?year=2005).

Another workaround is to put (a redundant) annotation:

@SpringBootTest(webEnvironment = RANDOM_PORT)
@ActiveProfiles("test")
@Sql(value = "classpath:sql/my_sql.sql")
@Import({TestConfig.class})
@AutoConfigureWebTestClient // the DefaultWebTestClient will be injected with different property values.

In this case the DefaultWebTestClient is injected with private final UriComponentsBuilder baseUri; equals to null, then the methods:

S uri(URI uri);

S uri(String uri, Object... uriVariables);

are consistent: both return the URI without the base URI, but in this case everything works.

Comment From: sbrannen

I've edited your comment to improve the formatting. You might want to check out this Mastering Markdown guide for future reference.

Specifically, please avoid the use of @-mentions for annotations. Instead, please ensure that annotations are formatted as literals or code snippets.

Comment From: sbrannen

As stated in the Javadoc for WebTestClient.UriSpec.uri(String, Object...):

Specify the URI for the request using a URI template and URI variables. If a UriBuilderFactory was configured for the client (e.g. with a base URI) it will be used to expand the URI template.

By passing uri.toString(), you end up invoking this method which treats the URI string as a URI template and applies the base URI.

As stated in the Javadoc for WebTestClient.UriSpec.uri(URI):

Specify the URI using an absolute, fully constructed URI.

The URI used in your first example is not absolute and fully constructed, and the base URI is not applied.

Thus, the behavior you are experiencing is expected and by design; however, I think the Javadoc for WebTestClient.UriSpec.uri(URI) should state the difference more explicitly, and I'll repurpose this issue to address that.

Comment From: SimoneGiusso

The URI used in your first example is not absolute and fully constructed, and the base URI is not applied.

This example works by adding the @AutoConfigureWebTestClient. In this case the base URI is not applied but the test pass. This is not specified in the documentation neither. I think this is not expected and it's not coherent from a developer prospective:

  • Without @AutoConfigureWebTestClient and with @SpringBootTest(webEnvironment = RANDOM_PORT), the tests don't work without the base URI
  • With @AutoConfigureWebTestClient and @SpringBootTest(webEnvironment = RANDOM_PORT), the tests work without the base URI

Comment From: sbrannen

This example works by adding the @AutoConfigureWebTestClient. In this case the base URI is not applied but the test pass. This is not specified in the documentation neither. I think this is not expected and it's not coherent from a developer prospective:

If you feel that something can be documented better in Javadoc or in the reference docs for the core Spring Framework, please let us know in this issue tracker.

Regarding the behavior of WebTestClient in combination with @AutoConfigureWebTestClient and @SpringBootTest, please open an issue in the Spring Boot issue tracker.

Thanks