Mulgard
Mulgard

Reputation: 10589

Testing Mono and Flux using Mockito

Im currently writing some basic unit tests for my REST-Endpoints. I use Mockito for that. Here one example:

@MockBean
private MyService service;

@Test
public void getItems() {
    Flux<Item> result = Flux.create(sink -> {
        sink.next(new Item("1"));
        sink.next(new Item("2"));
        sink.complete();
    });

    Mono<ItemParams> params = Mono.just(new ItemParams("1"));

    Mockito.when(this.service.getItems(params)).thenReturn(result);

    this.webClient.post().uri("/items")
            .accept(MediaType.APPLICATION_STREAM_JSON)
            .contentType(MediaType.APPLICATION_STREAM_JSON)
            .body(BodyInserters.fromPublisher(params, ItemParams.class))
            .exchange()
            .expectStatus().isOk()
            .expectBodyList(Item.class).isEqualTo(Objects.requireNonNull(result.collectList().block()));
}

This implementation leads to the following error:

java.lang.AssertionError: Response body expected:<[Item(name=1), Item(name=2)]> but was:<[]>

> POST /items
> WebTestClient-Request-Id: [1]
> Accept: [application/stream+json]
> Content-Type: [application/stream+json]

Content not available yet

< 200 OK
< Content-Type: [application/stream+json;charset=UTF-8]

No content

When I exchange the parameter in the Mockito Statement with Mockito.any()

Mockito.when(this.service.getItems(Mockito.any())).thenReturn(result);

The test runs through successfully. That means that for some reason the params I put into the Mockito Statement isnt equal to the params object which I put into BodyInserters.fromPublisher(params, ItemParams.class)

How am I supposed to test my functionality then?

EDIT

REST-Endpoint

@PostMapping(path = "/items", consumes = MediaType.APPLICATION_STREAM_JSON_VALUE, produces = MediaType.APPLICATION_STREAM_JSON_VALUE)
public Flux<Item> getItems(@Valid @RequestBody Mono<ItemParams> itemParms) {
    return this.service.getItems(itemParms);
}

Upvotes: 8

Views: 32131

Answers (1)

Maciej Kowalski
Maciej Kowalski

Reputation: 26522

Wouldn't the actual object, @RequestBody Mono<ItemParams> itemParms, be different than the one you create and pass in the test?

You could take advantage of thenAnswer in order to verify the content of the object that is actually passed to the service:

Mockito.when(this.service.getItems(Mockito.any()))
       .thenAnswer(new Answer<Flux<Item>>() {

    @Override
    public Flux<Item> answer(InvocationOnMock invocation) throws Throwable {
        Mono<ItemParams> mono = (Mono<ItemParams>)invocation.getArgument(0);

        if(/* verify that paseed mono contains new ItemParams("1")*/){
          return result;
        }

        return null;
    }
});

Upvotes: 5

Related Questions