如何让aspectj在webtestclient中工作?

How to let aspectj worked in webtestclient?

我有一些 apis 由 spring webflux 实现。现在我需要写一些 UT 来测试它。我用spock写UT代码,用WebTestClient.bindToRouterFunction方法创建一个mock server。它也有效。但是我发现我有一个 ParaCheckAspect 来检查 api 的参数,它不起作用,因为我还没有创建 Spring IOC。我必须查看 WebTestClient apis,它没有任何 api 来注册我的 ParaCheckAspect。如果您知道解决问题的方法,请告诉我。

我看过 spring 文档 https://docs.spring.io/spring/docs/current/spring-framework-reference/testing.html#webtestclient。它没有这方面的有效信息。

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

}

这还不是答案,目前只是与 OP 通信的一种方式,因为我需要 space 到 post 代码和调用堆栈,这是不可能在评论中。

免责声明:我从未使用过Gradle(仅 Maven)并且对 Webflux 了解为零。但有几点我可以说:

  • 克隆您的项目时,我注意到的第一件事是您在 build.gradle 中忘记了 apply plugin: "groovy"。没有它,你的 Spock 测试甚至不会被编译并且 运行.
  • 添加 Groovy 插件后,运行测试产生以下执行:
Method org.springframework.test.web.reactive.server.WebTestClient.bindToRouterFunction(Lorg/springframework/web/reactive/function/server/RouterFunction;)Lorg/springframework/test/web/reactive/server/
java.lang.IncompatibleClassChangeError: Method org.springframework.test.web.reactive.server.WebTestClient.bindToRouterFunction(Lorg/springframework/web/reactive/function/server/RouterFunction;)Lorg/springframework/test/web/reactive/server/
    at com.winston.webflux.UserHandlerSpec.setup(UserHandlerSpec.groovy:25)

com.winston.webflux.UserHandlerSpec > test userSave FAILED
    java.lang.IncompatibleClassChangeError at UserHandlerSpec.groovy:25

这是你的问题吗?您从未说过您实际遇到的问题,只是 "AspectJ"(您真正的意思是 Spring AOP)在您的测试中不起作用。

还有一个示例应用程序。我可以启动它,但是我需要做什么才能启动这个方面?抱歉,我真的不是 Spring 人,我只是 AOP 专家,也了解 Spock。所以请先帮我理解问题。如果我在浏览器中打开 http://localhost:8080/user/,我只会得到一个 "Whitelabel Error Page",控制台上没有任何日志输出。

如果您正在使用 spring,您应该包括 spock-spring 模块,这会为您的 Specification 添加 spring 支持。然后你需要使用 @SpringBootTest 或类似的 spring 注释,例如@WebFluxTest,并注入您的处理程序。这样 spring 创建实例并应用 AOP 拦截器。