Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WebTestClient base path is not set to the application context path #24168

Closed
20fps opened this issue Nov 6, 2020 · 9 comments
Closed

WebTestClient base path is not set to the application context path #24168

20fps opened this issue Nov 6, 2020 · 9 comments
Assignees
Labels
type: bug A general bug
Milestone

Comments

@20fps
Copy link

20fps commented Nov 6, 2020

For TestRestClient context path is autoconfigured as base by default, it is a bit confusing to have both clients autoconfigured with the different base paths.
Also I don't see any possibility to configure base path for WebTestClient since it is hardcoded on creation:
return builder.baseUrl(baseUrl).build();

Now I understand why servlet.contextPath is not used since it is not reactive based, but if it is possible to use for non-reactive it should be at least configurable.

I'd like to have possibility to customize base path for WebTestClient.

@sbrannen
Copy link
Member

sbrannen commented Nov 8, 2020

For TestRestClient context path is autoconfigured as base by default

Are you referring to the TestRestTemplate in Spring Boot Test?

@20fps
Copy link
Author

20fps commented Nov 8, 2020

For TestRestClient context path is autoconfigured as base by default

Are you referring to the TestRestTemplate in Spring Boot Test?

Yes

@rstoyanchev
Copy link
Contributor

@20fps this can be done currently as follows:

MockMvcBuilders.webAppContextSetup(this.wac)
        .defaultRequest(get("/").contextPath("/myapp"))
        .build();

This should work well as long as you want the same context path for all tests in the fixture but it would be less convenient for a one-off test case. I suppose we could expose convenience methods directly on MockMvcServerSpec for this.

@rstoyanchev rstoyanchev self-assigned this Nov 9, 2020
@rstoyanchev
Copy link
Contributor

rstoyanchev commented Nov 9, 2020

On second thought, exposing a convenience method in MockMvcServerSpec is just that, a convenience over doing the same via defaultRequest(..). In other words there is no way to set this per request and it must be set per WebTestClient instance instead. This makes sense since with just MockMvc you are on the server side each time you set up an HttpServletRequest and that gives you an opportunity to set the contextPath, while with WebTestClient you are on the client side and there is no way to set the contextPath which is a server side concept.

So I'm closing this without any further changes for now in favor of the sample shown above which is also consistent with how it's set at the MockMvc level when using just MockMvc.

@20fps
Copy link
Author

20fps commented Nov 9, 2020

@rstoyanchev what do you mean by MockMvc?
I'm using @SpringBootTest with random port and WebTestClient as a client for my integration tests.
MockMvc should not be used for integration tests.

@rstoyanchev rstoyanchev reopened this Nov 10, 2020
@rstoyanchev
Copy link
Contributor

I misunderstood the scenario. Disregard my previous comments.

I don't see any possibility to configure base path for WebTestClient since it is hardcoded on creation:
return builder.baseUrl(baseUrl).build();

Can you clarify where this is hard-coded?

@20fps
Copy link
Author

20fps commented Nov 10, 2020

Can you clarify where this is hard-coded?

Sure
org.springframework.boot.test.web.reactive.server.WebTestClientContextCustomizer.WebTestClientFactory#getObject
Here's the code:

@Override
public WebTestClient getObject() throws Exception {
  if (this.object == null) {
    this.object = createWebTestClient();
  }
  return this.object;
}

private WebTestClient createWebTestClient() {
  boolean sslEnabled = isSslEnabled(this.applicationContext);
  String port = this.applicationContext.getEnvironment().getProperty("local.server.port", "8080");
  String baseUrl = (sslEnabled ? "https" : "http") + "://localhost:" + port;
  WebTestClient.Builder builder = WebTestClient.bindToServer();
  customizeWebTestClientBuilder(builder, this.applicationContext);
  customizeWebTestClientCodecs(builder, this.applicationContext);
  return builder.baseUrl(baseUrl).build();
}

@bclozel
Copy link
Member

bclozel commented Nov 10, 2020

@20fps I have a hard time following this.
It's not clear if you'd like another extension point in WebTestClient itself to further customize or reset the base URL of the client, or if you disagree with Spring Boot's defaults in this case.

Also, I'm not sure I understand how TestRestTemplate and WebTestClient are behaving differently and where the behavior should be aligned.

Maybe you could provide two code snippets, one @Test method using TestRestTemplate and another using WebTestClient, and explain what is the difference about base URLs. I also fail to understand how the Servlet context path is playing a role here and how that applies to the WebFlux case.

Thanks!

@20fps
Copy link
Author

20fps commented Nov 10, 2020

@bclozel sure, here is an example:

@SpringBootTest(
    webEnvironment = WebEnvironment.RANDOM_PORT,
    classes = SampleApplicationTest.SampleApplication.class)
@TestPropertySource(properties = "server.servlet.context-path=/test")
class SampleApplicationTest {

  @Autowired
  private TestRestTemplate testRestTemplate;
  @Autowired
  private WebTestClient webTestClient;

  @Test
  void shouldReturnResourcesUsingTestRestTemplate() {
    var actual = testRestTemplate.getForEntity("/resources", String.class);

    assertThat(actual.getStatusCode()).isEqualTo(OK);
    assertThat(actual.getBody()).isEqualTo("test-resource");
  }

  // will fail with 404 cos context path is not configured
  @Test
  void shouldReturnResourcesUsingWebTestClient() {
    webTestClient.get().uri("/resources").exchange()
        .expectStatus().isOk()
        .expectBody(String.class).isEqualTo("test-resource");
  }

  @SpringBootApplication
  static class SampleApplication {

    static void main(String[] args) {
      SpringApplication.run(SampleApplication.class, args);
    }

    @RestController
    static class Controller {
      @GetMapping("/resources")
      String resources() {
        return "test-resource";
      }
    }
  }
}

I'd like to have possibility to customize baseUrl for WebTestClient to include contextPath just like for TestRestTemplate.

From the example above, let's assume random port will be 8080:

  • for TestRestTemplate base path is configured as http://localhost:8080/test and passing url as /resources will be resolved as request to http://localhost:8080/test/resources
  • for WebTestClient base path is configured as http://localhost:8080 and the same /resources will be resolved as request to http://localhost:8080/resources and 404 response

I'd like to have possibility to customize base path as generated_host + custom_path without having to create WebTestClient instance by my own.

@bclozel bclozel changed the title Provide possibility to configure context/base path for WebTestClient WebTestClient base path is not set to the application context path Nov 16, 2020
@bclozel bclozel transferred this issue from spring-projects/spring-framework Nov 16, 2020
@bclozel bclozel added the type: bug A general bug label Nov 16, 2020
@bclozel bclozel added this to the 2.2.x milestone Nov 16, 2020
@philwebb philwebb modified the milestones: 2.2.x, 2.3.x Dec 16, 2020
@mbhave mbhave self-assigned this Jan 6, 2021
@mbhave mbhave closed this as completed in 73a2a4b Jan 7, 2021
@mbhave mbhave modified the milestones: 2.3.x, 2.3.8 Jan 7, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: bug A general bug
Projects
None yet
Development

No branches or pull requests

6 participants