Search code examples
javaunit-testinggroovyspockspring-cloud-gateway

Unit testing spring cloud gateway filters with spock


I'm adding cookies in gateway response using reactive global filters as:

chain.filter(exchange).then(<a mono relevant to response>)

When I'm trying to test this using spock then method is not invoked from the stubbed Mono.

The filter itself:

@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*
    });
}

This test passes despite 0 * _ in the end:

@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 * _
}

But in the code I invoke .then from the mono returned from .filter method.

Why isn't mono.then() taken into account? Of course when I try to test all the underlying logic - spock doesn't find interactions.


Solution

  • Losing hope to test the filter end-to-end I've extracted my runnable in a separate package private method and tested it without Monos and any other reactive things.

    The code in my filter now looks like:

    @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 ....
        };
    }
    

    Any further clues and refactoring proposals are appreciated.