Spent significant time in dead SO 1-4 year old threads to come here, the problem is that even old hack no longer works in version 3.1.0 - I don't really know how to send a web request to @SpringBootTest application with web environment at all anymore. Who is WebTestClient is created for if it is limited to @WebFluxTest? When E2E and testcontainers became as relevant as ever, the spring fundamental actor of testing is severely limited to working with just two segments of the system - user defined beans and web - trying to do anything else, like test both data and web aspects for the system.
E.G. A project with a test working test client version hack SB 2.2.7 release:
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK)
class SomeE2ETest
@Autowired
ApplicationContext ctx;
WebTestClient webTestClient;
@BeforeEach
void setup() {
webTestClient = WebTestClient.bindToApplicationContext(ctx).build();
}
E.G. A kotlin project with working SBB 2.4.4 release:
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class SomeOtherE2ETests(
@Autowired private val someRepository: SomeRepository,
@Autowired private val client: WebTestClient,
This is what I expect to work in SB 3.1.0:
``` @ContextConfiguration(initializers = MySQLTestContainerInitializer.class) @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) public class TournamentsMatchesE2ETest {
@Autowired
ApplicationContext ctx;
// @Autowired WebTestClient webTestClient;
@BeforeEach
void before() {
webTestClient = WebTestClient.bindToApplicationContext(ctx).build();
}
@Test
public void saveAMatch(){
String json = TestFileUtils.loadFile("requests/match_request.json");
webTestClient.post().uri("/v1/matches").contentType(MediaType.APPLICATION_JSON)
...
```
If I use the code as is - with binding to application ctx, I get:
No bean named 'webHandler' available
org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'webHandler' available
If I use the @Autowired the context builds successfully but test gives me 404 for my test requests, because:
2023-05-30T03:30:59.474+01:00 TRACE 274243 --- [ Test worker] o.s.w.s.f.support.RouterFunctionMapping : 0 RouterFunction(s) in 'routerFunctionMapping'
My routing config is, no rocket science here:
@Configuration
public class RoutingConfig {
@Bean
public RouterFunction<ServerResponse> routes(TournamentMatchesHandler tournamentMatchesHandler, TournamentMatchesLicensesHandler tournamentMatchesLicensesHandler) {
return RouterFunctions.route(GET(API_V_1_MATCHES_API), tournamentMatchesHandler::handleGetMatches)
.andRoute(POST(API_V_1_MATCHES_API), tournamentMatchesHandler::handlePostMatch)
.andRoute(POST(API_V_1_MATCHES_API + "/{" + matchIdPathVar + "}/licenses"), tournamentMatchesLicensesHandler::handleMatchLicense)
.andRoute(POST(API_V_1_TOURNAMENTS_API + "/{" + tournamentIdPathVar + "}/licenses"), tournamentMatchesLicensesHandler::handleMatchTournamentLicense);
}
}
Obviously the router function above is picked up by @WebFluxTest and RouterFunctionMapping prints 4 entries (as expected) but even here we need hack:
@WebFluxTest
@ContextConfiguration(classes = RoutingConfig.class) // ... I am not even going to ask why this is needed ...
In a nutshell I feel caged because conceptually I need :
@WebFluxTest and @DataR2dbcTest together and a test client working together which is responsibility of @SpringBootTest but the fella forgot how to be friends with the client...
and my hands are shackled from one direction or another.
If I try to use classes in @ContextConfiguration to add my RouterConfig manually all the beans web config beans are discarded and missing "ServletFactoryYadaYadaBean".
So the question stays:
How to test SpringBootTest application with web context and web client? Why the "regression" to previous versions? Can I have at least a hack back, PLEASE.
Comment From: wilkinsona
Unfortunately, there's nothing particularly civil about what you've written. If you are interested in a constructive discussion then we will be more than happy to help. Unfortunately, saying that something results in a "brutalsky middle finger" and that it's a "total disaster" doesn't set a constructive tone as there's nothing there that we can act upon.
Unfortunately, I don't think I understand exactly what you're trying to do so I can't offer any suggestions on what may have regressed and why. If you would like us to spend some more time investigating, please spend some time providing a complete yet minimal sample that reproduces the problem. You can share it with us by pushing it to a separate repository on GitHub or by zipping it up and attaching it to this issue. To illustrate the regression, this sample should include code that works with Spring Boot 2.x yet fails with 3.1.
Comment From: curiousconcept
Unfortunately, there's nothing particularly civil about what you've written. If you are interested in a constructive discussion then we will be more than happy to help. Unfortunately, saying that something results in a "brutalsky middle finger" and that it's a "total disaster" doesn't set a constructive tone as there's nothing there that we can act upon.
Unfortunately, I don't think I understand exactly what you're trying to do so I can't offer any suggestions one what may have regressed and why. If you would like us to spend some more time investigating, please spend some time providing a complete yet minimal sample that reproduces the problem. You can share it with us by pushing it to a separate repository on GitHub or by zipping it up and attaching it to this issue. To illustrate the regression, this sample should include code that works with Spring Boot 2.x yet fails with 3.1.
I believe the problem is clear. I want to use @SpringBootTest with WebTestClient. I was able to do that in earlier versions of SB and I can't do that in version 3.
I will provide .zip s asap. if they somehow explain it better..
Comment From: curiousconcept
@wilkinsona Sorry for delay, I finally found the offender after starting fresh, I had rogue starter which I accidentally added via spring initalizr:
implementation 'org.springframework.boot:spring-boot-starter-data-rest'
This breaks initialization of test web client with:
No bean named 'webHandler' available
org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'webHandler' available
Is this something you aware about? Attaching the code.
Comment From: curiousconcept
Please ignore mysql stuff(as fresh project @SpringBootTest and WebTestClient worked so I tried to match the diffs to my project and thought that this is a culprit first however it is the starter dependency).
Also, I fully realize that the project isn't compatible with WebFlux, it would be nice to have safeguard between starters, or some validation what is allowed and expected to work or what not, it's incredibly hard to debug stuff like this in a big project, though I fully acknowledge it is my fault for adding non compatible starter...
Sidenote for anyone interested if it is ever going to be supported:
https://github.com/spring-projects/spring-data-rest/issues/1299
The answer is never. Though I always found that spring data rest of a very limited use for production code.
Comment From: wilkinsona
I'm not sure that there's much more that we can do here. We've already documented that MVC is preferred when both WebFlux and MVC are present:
Adding both spring-boot-starter-web and spring-boot-starter-webflux modules in your application results in Spring Boot auto-configuring Spring MVC, not WebFlux. This behavior has been chosen because many Spring developers add spring-boot-starter-webflux to their Spring MVC application to use the reactive WebClient. You can still enforce your choice by setting the chosen application type to
SpringApplication.setWebApplicationType(WebApplicationType.REACTIVE).
I don't think we can have a safeguard between starters as web and webflux is a valid combination when using WebClient in a Servlet-based app. One thing that we could do is to clarify that spring-boot-starter-data-rest uses the Servlet-based web stack. I've opened #35678 to do that.