首页 > 解决方案 > 使用 gradle 和 JUnit5 进行 ByteBuddy 代理测试

问题描述

当我尝试测试使用 ByteBuddy 编写的 Java 代理时,我遇到了一些奇怪的行为

代理拦截带注释的方法/类并分析它们,没什么复杂的

class ByteInstrumentationConfigurer implements BootstrapConfigurer {

    @Override
    void init(...) {
        def instrumentation = ByteBuddyAgent.install()
        new AgentBuilder.Default()
                .type(isAnnotatedWith(TimeProfiling.class))
                .transform((builder, typeDescription, classLoader, module) ->
                        builder.method(not(isAnnotatedWith(Generated))) //ignore groovy generated methods (getMetaClass, etc.)
                            .intercept(MethodDelegation.to(TimeProfilingInterceptor.class)))
                .with(stdoutToLoggerWriter.withTransformationsOnly())
                .installOn(instrumentation) 

我有一些单元测试,我验证拦截器方法被调用

class TimeProfilingInterceptorTest {

    static MockedStatic<TimeProfilingInterceptor> timeProfilingInterceptorMockedStatic

    static {
        //agent installation happens here
        new ByteInstrumentationConfigurer().init([:], [:])
        timeProfilingInterceptorMockedStatic = mockStatic(TimeProfilingInterceptor, CALLS_REAL_METHODS)
    }
    
    @Test
    void profilingEnabledClassLevelTest() {
        //some mocking for my classes here
        testCallingComponent.callClassLevelComponentMethod()
        timeProfilingInterceptorMockedStatic.verify(()->
                TimeProfilingInterceptor.measureAndLogExecutionTime(any(),any(),any()),times(2))
}

而现在,当我使用从 IDEA 开始这个测试时,我看到,我的 2 个课程被转换了

[字节好友] 转换 com.kmslh.manager.profiling.components.MethodLevelTimeProfilingComponent [sun.misc.Launcher$AppClassLoader@18b4aac2, null, Thread[main,5,main], loaded=false]

[字节好友] 转换 com.kmslh.manager.profiling.components.ClassLevelTimeProfilingComponent [sun.misc.Launcher$AppClassLoader@18b4aac2, null, Thread[main,5,main], loaded=false]

但是如果我使用gradletest\build 任务运行这个测试 - 没有类转换。如果我输出完整信息 - 我看到这种情况下的类加载器是org.codehaus.groovy.runtime.callsite.CallSiteClassLoader.

[字节好友] 发现 com.kmslh.manager.profiling.components.ClassLevelTimeProfilingComponent$exposedMethod [org.codehaus.groovy.runtime.callsite.CallSiteClassLoader@3b1a332, null, Thread[Test worker,5,main], loaded=false] [字节好友] IGNORE com.kmslh.manager.profiling.components.ClassLevelTimeProfilingComponent$exposedMethod [org.codehaus.groovy.runtime.callsite.CallSiteClassLoader@3b1a332, null, Thread[Test worker,5,main], loaded=false] [字节好友] 完成 com.kmslh.manager.profiling.components.ClassLevelTimeProfilingComponent$exposedMethod [org.codehaus.groovy.runtime.callsite.CallSiteClassLoader@3b1a332, null, Thread[Test worker,5,main], loaded=false]

不确定这是否是一个问题,但我没有想法。我还尝试将测试重写为 Java - 没有结果。

有什么建议可以尝试吗?

更新 1

从我所看到的 - 当测试从 gradle 开始时 - 没有auxiliary创建类

更新 2

我运行 gradle 任务-verbose:class并查看,我的类在开始检测之前加载 [Loaded com.kmslh.manager.profiling.components.ClassLevelTimeProfilingComponent from file:/C:/Users/.../build/classes/groovy/main/]

当 IDEA 运行测试时(将其打包到 jar 中并运行 jar)- 类在检测后加载

更新 3

[从文件加载 com..ClassLevelTimeProfilingComponent:/C:/Users/../build/classes/groovy/test/]

[从VM_RedefineClasses加载 com.... ClassLevelTimeProfilingComponent ]

[字节好友] TRANSFORM com....ClassLevelTimeProfilingComponent [sun.misc.Launcher$AppClassLoader@73d16e93, null, Thread[Test worker,5,main], loaded=true]

[从文件加载 com....ClassLevelTimeProfilingComponent$exposedMethod:/C:/Users/79270/IdeaProjects/kms-trunk/KMS-Manager/build/classes/groovy/test/]

标签: javagradlegroovyjunit5byte-buddy

解决方案


从您的日志中,Gradle 测试运行的类加载器与您的示例运行的类加载器不同。因此,我假设您的匹配器对正在使用的类加载器很敏感。此外,请确保您的忽略匹配器不会在并行测试中排除类加载器。


推荐阅读