繁体   English   中英

Spring Reactor中的模拟服务

[英]Mock services in Spring Reactor

让我们看一下这个简单的方法:

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可以是惰性的,但不能简单地调用运算符。 您急切地调用将返回惰性Mono的方法,从而组装了处理管道。

如果您内联代码,我认为它会变得更加清晰:

    //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隐藏了一个不是惰性的源(例如,从CompletableFuture改编的Mono否则问题不是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();

thenReturn不是因为抛出错误! 您需要使用thenThrow()并且也不需要为service2编写模拟方法,只需验证已调用了

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM