Search code examples
springaspectjspockspring-webflux

How to let aspectj worked in webtestclient?


I have some apis implements by spring webflux. Now i need to write some UT to test it. I write the UT code by spock, and create a mock server by the method WebTestClient.bindToRouterFunction. It worked as well. But i found that i have an ParaCheckAspect to check the api's parameters, it doesn't work because I have not created Spring IOC . I have to look the WebTestClient apis, it not has any api to register my ParaCheckAspect. Please tell me if you know any way to resolve it.

I have look the spring document https://docs.spring.io/spring/docs/current/spring-framework-reference/testing.html#webtestclient. It not has effective info for this.

/**
 * check Parameters is validate
 */
@Aspect
@Slf4j
@Component
public class ParaCheckAspect {

    @Around("execution (* com.winston.springboot.handler..*(..))")
    public Object validate(ProceedingJoinPoint point) throws Throwable {
        for (int i = 0; i < point.getArgs().length; i++) {
            if (point.getArgs()[i] instanceof Mono) {
                point.getArgs()[i] = ((Mono<?>) point.getArgs()[i])
                    .doOnNext(this::check)
                    .onErrorResume(e -> Mono.error(new ResponseStatusException(HttpStatus.BAD_REQUEST,e.getMessage())));
            } else if (point.getArgs()[i] instanceof Flux) {
                point.getArgs()[i] = ((Flux<?>) point.getArgs()[i])
                    .doOnNext(this::check)
                  .onErrorResume(e -> Mono.error(new ResponseStatusException(HttpStatus.BAD_REQUEST,e.getMessage())));
            }
        }
        return point.proceed(point.getArgs());
    }
    private void check(Object obj) {
        //some validator code

    }
}

import com.winston.springboot.config.routers.UserRouter
import com.winston.springboot.entity.User
import com.winston.springboot.handler.UserHandler
import org.mockito.InjectMocks
import org.mockito.MockitoAnnotations
import org.springframework.test.web.reactive.server.WebTestClient
import org.springframework.web.reactive.function.BodyInserters
import spock.lang.Shared
import spock.lang.Specification

class UserHandlerSpec extends Specification {

    @Shared
    WebTestClient testClient

    @InjectMocks
    UserHandler userHandler

    void setup() {
        MockitoAnnotations.initMocks(this)
        def function = routeFunction()
        def routeFunctionSpec = WebTestClient.bindToRouterFunction(function)
        testClient = routeFunctionSpec
                .configureClient()
                .baseUrl("http://127.0.0.1:8089")
                .build()
    }

    def 'test userSave'() {
        given:
        User user = User.builder().name("lina").age(10).build()
        when:
        testClient.post().uri("/user")
                .body(BodyInserters.fromObject(user))
                .exchange()
                .expectStatus()
                .isOk()
                .expectBody(User.class)
                .returnResult();
        then:
        noExceptionThrown();
    }

    def routeFunction() {
      return  new UserRouter().userRouterFunction(userHandler);
    }

}


Solution

  • If you are using spring, you should include the spock-spring module, this adds spring support to your Specification. Then you need to use @SpringBootTest or a similar spring annotation, e.g. @WebFluxTest, and inject your handlers. This ways spring creates the instances and applies the AOP interceptors.