Test web layer of a super simple sample application with WebFluxTest.
In this sample application there is only one endpoint returning some information about a user. We handle two case :
- We find the user :
ServerResponse.ok()
- We didn't find the user :
ServerReponse.notFound()
@Configuration
class UserAccountWebConfiguration {
private Mono<ServerResponse> findUserInfo(ServerRequest serverRequest, UserAccountFacade userAccountFacade) {
return userAccountFacade.findUserInfo(serverRequest.pathVariable("userId"))
.flatMap(userInfoDto -> ServerResponse.ok()
.contentType(MediaType.APPLICATION_JSON)
.body(Mono.just(userInfoDto), UserInfoDto.class))
.switchIfEmpty(ServerResponse.notFound().build());
}
@Bean
RouterFunction<ServerResponse> route(UserAccountFacade userAccountFacade) {
return RouterFunctions.route()
.GET("/info/{userId}", serverRequest -> findUserInfo(serverRequest, userAccountFacade))
.build();
}
}
The project goal is to show how to use WebFluxTest, so we just create a fake facade that return hard coded data. (On a real application we could have a database and use a spring Repository
)
public class UserAccountFacade {
public Mono<UserInfoDto> findUserInfo(String userId) {
return Mono.just(new UserInfoDto("hardCodedName", "hardCodedCity"));
}
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserInfoDto {
private String name;
private String city;
}
- Annotate the test class with
@WebFluxTest
Import
our web configuration classAutowire
theWebTestClient
, needed to make requestMockBean
ourFacade
, needed to test our web layer as ablack box
, we want to choose what the facade return to test all case
@WebFluxTest
@Import(UserAccountWebConfiguration.class)
class UserAccountWebConfigurationTest {
@Autowired
private WebTestClient webTestClient;
@MockBean
private UserAccountFacade userAccountFacade;
}
We create a first test case to check the case where we correctly find the user. So we use Mockito
to set what the method findUserInfo
return, on this test it return some fake user info.
We then make the request and specify what we expect :
- There is a GET endpoint at
/info/{userId}
- The server respond with status code
isOk()
- The server respond with header
APPLICATION_JSON
- The body can be mapped to a UserInfoDto object
- The UserInfoDto returned is what we expect
At the end on this test we also check that the method findUserInfo
is called once.
@Test
void should_find_user_info() {
String userId = "randomUserId";
UserInfoDto expectedUserInfoDto = new UserInfoDto("Anthony", "Paris");
when(userAccountFacade.findUserInfo(userId)).thenReturn(
Mono.just(expectedUserInfoDto)
);
webTestClient.get().uri("/info/" + userId)
.accept(MediaType.APPLICATION_JSON)
.exchange()
.expectStatus().isOk()
.expectHeader().contentType(MediaType.APPLICATION_JSON)
.expectBody(UserInfoDto.class)
.value(userInfoDto -> assertEquals(expectedUserInfoDto, userInfoDto));
verify(userAccountFacade, times(1)).findUserInfo(userId);
}
In our next test case we will check for the case where we didn't find the user, so as before we set what findUserInfo
return and make the request but this time we expect the server will respond with status code isNotFound()
.
@Test
void should_not_find_user_info() {
String userId = "randomUserId";
when(userAccountFacade.findUserInfo(userId)).thenReturn(Mono.empty());
webTestClient.get().uri("/info/" + userId)
.accept(MediaType.APPLICATION_JSON)
.exchange()
.expectStatus().isNotFound();
verify(userAccountFacade, times(1)).findUserInfo(userId);
}