Java 使用spock对spring云网关过滤器进行单元测试

Java 使用spock对spring云网关过滤器进行单元测试,java,unit-testing,groovy,spock,spring-cloud-gateway,Java,Unit Testing,Groovy,Spock,Spring Cloud Gateway,我使用反应式全局筛选器在网关响应中添加cookie,如下所示: chain.filter(exchange).then(<a mono relevant to response>) chain.filter(交换).then() 当我尝试使用spock测试时,不会从stubbed Mono调用该方法 过滤器本身: @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterCh

我使用反应式全局筛选器在网关响应中添加cookie,如下所示:

chain.filter(exchange).then(<a mono relevant to response>)
chain.filter(交换).then()
当我尝试使用spock测试时,不会从stubbed Mono调用该方法

过滤器本身:

@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
    return chain.filter(exchange)
            .then(refreshCookiesMono(exchange));
}

private Mono<Void> refreshCookiesMono(ServerWebExchange exchange) {
    return Mono.fromRunnable(() -> {
        //interactions with *exchange* and *chain*
    });
}
@覆盖
公共Mono筛选器(服务器WebExchange exchange、网关筛选器链){
返回链。过滤器(交换)
。然后(交换);
}
专用Mono刷新CookiesMono(服务器WebExchange exchange){
返回Mono.fromRunnable(()->{
//与*交换*和*链的交互*
});
}
尽管最终为0*uu,但该测试通过:

@Subject
CookieFilter cookieFilter = new CookieFilter(cookieHelper)
...
ServerWebExchange exchange = Mock ServerWebExchange
GatewayFilterChain chain = Mock GatewayFilterChain
Mono<Void> mono = Mock Mono

...

def "cookieFilter refreshes the cookie with a new value"() {
    given:

    when:
    cookieFilter.filter(exchange, chain)

    then:
    1 * chain.filter(exchange) >> mono
    0 * _
}
@Subject
CookieFilter CookieFilter=新CookieFilter(cookieHelper)
...
ServerWebExchange=Mock ServerWebExchange
网关过滤链=模拟网关过滤链
单声道=模拟单声道
...
def“cookieFilter使用新值刷新cookie”(){
鉴于:
什么时候:
cookieFilter.过滤器(交换、链)
然后:
1*链式过滤器(交换)>>mono
0 * _
}
但是在我调用的代码中,从.filter方法返回的mono

为什么不考虑mono.then()呢?当然,当我尝试测试所有底层逻辑时,spock没有找到交互。

chain.filter(exchange)
返回您模拟的mono实例

您没有在该模拟中指定任何期望值(我相信这就是您问题的答案),因此测试并没有真正检查筛选器,它只检查是否有一个调用
chain.Filter(exchange)

此外,Spock除了支持mock之外还支持存根,与许多其他框架不同,这些框架之间存在差异:

mock“更重”,您可以对它们进行验证(在“then”块中),stub更“轻”,您通常可以在“给定”块中指定对它们的期望。
通常,如果您想模拟某些交互并基于围绕此交互进行管理的协议进行测试,则使用mock,在其他情况下,stub更可取。

失去了端到端测试过滤器的希望我已在单独的包私有方法中提取了runnable,并在没有Monos和任何其他反应性内容的情况下对其进行了测试

我的过滤器中的代码现在看起来像:

@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
    return chain.filter(exchange)
            .then(Mono.fromRunnable(refreshCookies(exchange)));
}

Runnable refreshCookies(ServerWebExchange exchange) {
    return () -> {
        //magic happens here ....
    };
}
@覆盖
公共Mono筛选器(服务器WebExchange exchange、网关筛选器链){
返回链。过滤器(交换)
.然后(Mono.fromRunnable(刷新cookies(交换));
}
可运行的刷新cookies(ServerWebExchange){
返回()->{
//魔法在这里发生。。。。
};
}

任何进一步的线索和重构建议都将不胜感激。

我将交换和链作为模拟放在方法中。然后我在方法的主体中与它们交互。如果发生任何不匹配的交互,则测试最终应失败。它没有失败。当我将“1*mono.then()”添加到“then”部分时,测试失败,出现“调用太少…0”。测试中的
cookieFilter
来自哪里?它是另一个mock吗?@jaco0646不,它是一个实际的实现,使用其中一个mock作为依赖项。我已经更新了这个问题。所以,
cookieHelper
是一个模拟的,但是它没有作为测试的一部分被调用?@jaco0646,是的。filter(..)还返回mock和mono。then()交互也不考虑。