Closed
Description
Describe the bug
According to Spring Framework 5.3 Reference Documentation, I should be able to use WebTestClient to test Spring MVC applications. I tried it and it does not work if you have something reactive on classpath.
Caused by: java.lang.NullPointerException
at org.springframework.security.test.web.reactive.server.SecurityMockServerConfigurers$CsrfMutator.afterConfigurerAdded(SecurityMockServerConfigurers.java:259)
at org.springframework.test.web.reactive.server.DefaultWebTestClientBuilder.apply(DefaultWebTestClientBuilder.java:247)
at org.springframework.test.web.reactive.server.DefaultWebTestClient.mutateWith(DefaultWebTestClient.java:160)
at com.example.mvcwebtestclient.GreetingControllerTest.create(GreetingControllerTest.java:24)
The code in SecurityMockServerConfigurers (spring-security-test 5.4.2) is clearly buggy: it accesses a nullable argument httpHandlerBuilder
:
public void afterConfigurerAdded(WebTestClient.Builder builder,
@Nullable WebHttpHandlerBuilder httpHandlerBuilder, @Nullable ClientHttpConnector connector) {
CsrfWebFilter filter = new CsrfWebFilter();
filter.setRequireCsrfProtectionMatcher((e) -> ServerWebExchangeMatcher.MatchResult.notMatch());
httpHandlerBuilder.filters((filters) -> filters.add(0, filter));
}
Sample
build.gradle
dependencies {
implementation(platform("org.springframework.boot:spring-boot-dependencies:2.4.1"))
implementation 'org.springframework.boot:spring-boot-starter-data-mongodb-reactive'
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-webflux' // result of spring-framework#26308
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'io.projectreactor:reactor-test'
testImplementation 'org.springframework.security:spring-security-test'
}
GreetingController.java
@RestController
@RequestMapping("/greetings")
public class GreetingController {
@GetMapping
public Flux<String> findAll() {
return Flux.just("Hello", "world!");
}
}
GreetingControllerTest.java
@SpringBootTest
class GreetingControllerTest {
private WebTestClient client;
@Autowired
public void create(WebApplicationContext context) {
client = MockMvcWebTestClient.bindToApplicationContext(context)
.apply(springSecurity())
.configureClient()
.build()
.mutateWith(csrf());
}
@Test
public void findsAll() {
client.get().uri("/greetings")
.exchange()
.expectStatus().isOk();
}
}