簡體   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