本文介绍了弹簧反应堆中的模拟服务的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

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

    //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")));

一些操作符接受SupplierFunction,这为这种急切的构造风格提供了一种懒惰的替代方案。一种通用的方法是使用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();

这篇关于弹簧反应堆中的模拟服务的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-21 06:06