使用 Mockito 测试 Mono 和 Flux
Testing Mono and Flux using Mockito
我目前正在为我的 REST 端点编写一些基本的单元测试。为此,我使用 Mockito。举个例子:
@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()));
}
此实现会导致以下错误:
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
当我将 Mockito 语句中的参数与 Mockito.any()
交换时
Mockito.when(this.service.getItems(Mockito.any())).thenReturn(result);
测试顺利通过。
这意味着由于某种原因,我放入 Mockito
语句的 params
不等于我放入 BodyInserters.fromPublisher(params, ItemParams.class)
的 params
对象
那我应该如何测试我的功能?
编辑
REST 端点
@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);
}
实际对象 @RequestBody Mono<ItemParams> itemParms
会不会与您创建并通过测试的对象不同?
您可以利用 thenAnswer
来验证实际传递给服务的对象的内容:
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;
}
});
我目前正在为我的 REST 端点编写一些基本的单元测试。为此,我使用 Mockito。举个例子:
@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()));
}
此实现会导致以下错误:
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
当我将 Mockito 语句中的参数与 Mockito.any()
Mockito.when(this.service.getItems(Mockito.any())).thenReturn(result);
测试顺利通过。
这意味着由于某种原因,我放入 Mockito
语句的 params
不等于我放入 BodyInserters.fromPublisher(params, ItemParams.class)
params
对象
那我应该如何测试我的功能?
编辑
REST 端点
@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);
}
实际对象 @RequestBody Mono<ItemParams> itemParms
会不会与您创建并通过测试的对象不同?
您可以利用 thenAnswer
来验证实际传递给服务的对象的内容:
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;
}
});