本文介绍了弹簧反应堆中的模拟服务的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!
问题描述
我们来看一下这个简单的方法:
public Mono<SuccessResponse> doSomething(){
return service1.doSomething()
.then(service2.doSomething2())
.thenReturn(new SuccessResponse("Awesome")));
}
因此,基本上我想测试此方法的场景,在该场景中,service1.doSomething()将引发错误:
when(service1.doSomething()).thenReturn(Mono.error(new IllegalStateException("Something bad happened")));
when(service2.doSomething()).thenReturn(Mono.just(new SomeResponse()))
assertThatThrownBy(() -> testedService.doSomething().block())
.isExactlyInstanceOf(IllegalStateException.class);
verify(service2, never()).doSomething(); //Why this is executed!?
我的问题是为什么service2.doSomething()只执行一次?不应该执行它,因为service1.doSomething()在上面引发错误...
推荐答案
调用service2.doSomething()
方法的原因是Mono
可以是惰性的,而简单地调用运算符则不是。您正在急切地调用将返回LazyMono
s的方法,从而组装了一个处理管道。
如果您内联您的代码,我认为它会变得更清楚:
//exception is CREATED immediately, but USED lazily
return Mono.error(new IllegalStateException())
//mono is CREATED immediately. The data it will emit is also CREATED immediately. But it all triggers LAZILY.
.then(Mono.just(new SomeResponse()))
//note that then* operators completely ignore previous step's result (unless it is an error)
.thenReturn(new SuccessResponse("Awesome")));
一些操作符接受Supplier
或Function
,这为这种急切的构造风格提供了一种懒惰的替代方案。一种通用的方法是使用Mono.defer
:
public Mono<SuccessResponse> doSomething(){
return service1.doSomething()
.then(Mono.defer(service2::doSomething2))
.thenReturn(new SuccessResponse("Awesome")));
}
但我认为,除非service2
隐藏了一个不是懒惰的来源(例如。AMono
改编自CompletableFuture
),问题不是doSomething
而是考试。
使用service2
模拟,您实际上是在测试运算符链的程序集,但如果管道中的该步骤已实际执行,则不会。
reactor-test
中提供的一个技巧是将Mono.just
/Mono.error
包装在PublisherProbe
中。这可以用来模拟Mono
,但是添加了在Mono
执行时提供断言的特性:它订阅了吗?它是请求的吗?//this is ultimately tested by the assertThrownBy, let's keep it that way:
when(service1.doSomething()).thenReturn(Mono.error(new IllegalStateException("Something bad happened")));
//this will be used to ensure the `service2` Mono is never actually used:
PublisherProbe<SomeResponse> service2Probe = PublisherProbe.of(Mono.just(new SomeResponse()));
//we still need the mock to return a Mono version of our probe
when(service2.doSomething()).thenReturn(service2Probe.mono());
assertThatThrownBy(() -> testedService.doSomething().block())
.isExactlyInstanceOf(IllegalStateException.class);
//service2 might have returned a lazy Mono, but it was never actually used:
probe.assertWasNotSubscribed();
这篇关于弹簧反应堆中的模拟服务的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!