Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring webflux, testing `ServerResponse`

How can I test a handler method that receive ServerRequest and return Mono<ServerResponse> ?

I can create a ServerRequest via org.springframework.mock.web.reactive.function.server.MockServerRequest.builder(). And assert on the ServerResponse.statusCode(). However I would like to test the body of this ServerResponse but there is no way to extract it.

ServerResponse response = target.search(MockServerRequest.builder()
    .method(HttpMethod.GET)
    .build()
  ).block();

assertThat(response.statusCode()).isEqualTo(HttpStatus.OK);
//assertThat(response.body()).isNotNull();

I don't want to do a broader test with the WebTestClient, I would like to test all possible cases of response with unit tests.

Thanks

like image 568
gervais.b Avatar asked Aug 17 '18 10:08

gervais.b


3 Answers

So, it seems that the best solution is to use the WebTestClient. However this one can be used without a running server;

The spring-test module includes a WebTestClient that can be used to test WebFlux server endpoints with or without a running server.

-- https://docs.spring.io/spring/docs/5.0.0.BUILD-SNAPSHOT/spring-framework-reference/html/web-reactive.html#web-reactive-tests

The trick is to use the bindTo..() builder method. In my case bindToRouterFunction(new MyRouter(new MyHandler())) works well

like image 95
gervais.b Avatar answered Nov 18 '22 21:11

gervais.b


I had exactly the same question, because I don't want to start the entire Spring context for every test. Thanks for the info in the own-answer, this helped me. Here is a complete example including Mockito and JUnit5:

import java.util.Arrays;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.http.MediaType;
import org.springframework.test.web.reactive.server.WebTestClient;

@ExtendWith(MockitoExtension.class)
class UsersHandlerTest {
  @Mock
  UserRepository userRepository;

  WebTestClient client;

  @BeforeEach
  public void setUp() {
    UsersHandler usersHandler = new UsersHandler(userRepository);
    Router router = new Router(usersHandler);

    Mockito.when(userRepository.findAll()).thenReturn(
      Arrays.asList("", ""));

    client = WebTestClient.bindToRouterFunction(router.getUsers()).build();
  }

  @Test
  public void getCommands() {
    client.get().uri("/users")
      .accept(MediaType.APPLICATION_JSON_UTF8)
      .exchange()
      .expectStatus().isOk()
      .expectBody().json("{}");
  }
}
like image 4
Fletch Avatar answered Nov 18 '22 23:11

Fletch


I have asked a similar question insisting not to use WebTestClient. I have ended up answering my own question after discovering that it is possible to cast the response to a type that allows inspecting body (entity).

The magic line (Kotlin) is:

(serverResponse as EntityResponse<Fleet>).entity()

Edit: So for the case of expecting an empty body, you could do:

assert(serverResponse !is EntityResponse<*>)

Thanks for @andred for pointing this out

like image 3
alc0der Avatar answered Nov 18 '22 23:11

alc0der