【发布时间】:2020-07-08 12:43:01
【问题描述】:
我想做的是监控 JUnit 4 测试方法的调用。我必须自己这样做的原因是:我需要记录每个测试方法执行过程中执行的类。所以我需要在测试方法中插入一些指令,以便我知道测试何时开始/结束以及那些记录的类是由哪个测试实体执行的。所以我需要自己过滤测试方法。
其实我这样做的原因与问题无关,因为我没有在标题中提到“JUnit”、“test”。在其他类似情况下,问题仍然可能是问题。
我的情况是这样的:
public abstract class BaseTest {
@Test
public void t8() {
assert new C().m() == 1;
}
}
public class TestC extends BaseTest{
// empty
}
我还修改了 Surefire 的成员 argLine,以便在 Surefire 启动新的 JVM 进程执行测试时附加我的代理(预主模式)。
在我的代理类中:
public static void premain(String args, Instrumentation inst){
isPreMain = true;
agentArgs = args;
log("args: " + args);
parseArgs(args);
inst.addTransformer(new TestTransformer(), true);
}
我的变压器类:
public class TestTransformer implements ClassFileTransformer {
public byte[] transform(ClassLoader loader, String className,
Class<?> classBeingRedefined, ProtectionDomain protectionDomain,
byte[] classfileBuffer) throws IllegalClassFormatException {
log("TestTransformer: transform: " + className);
...
ClassReader cr = new ClassReader(classfileBuffer);
ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS);
RecordClassAdapter mca = new RecordClassAdapter(cw, className);
cr.accept(mca, 0);
return cw.toByteArray();
}
}
在我的 ClassVisitor 适配器类中:
class RecordClassAdapter extends ClassVisitor {
...
@Override
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
MethodVisitor mv = cv.visitMethod(access, name, desc, signature, exceptions);
mv = new RecordMethodAdapter (...);
return mv;
}
}
在我的 MethodVisitor 适配器类中:
class RecordMethodAdapter extends MethodVisitor {
public void visitCode() {
mv.visitCode();
if (isTestMethod){
mv.visitLdcInsn(methodName);
mv.visitMethodInsn(INVOKESTATIC, MyClass, "entityStarted",
"(Ljava/lang/String;)V", false);
}
}
}
遗憾的是,我发现抽象类不会进入transform 方法,因此我无法检测t8 方法。 TestC 应该作为测试类执行,但我永远无法监控 TestC.t8 的调用。
【问题讨论】:
-
如何注册/调用转换? (请用相关代码修改问题)
-
为什么? JUnit 4 已经提供了监控测试方法调用所需的一切。事实上,您可以使用不止一个内置功能来实现此类监控。
-
即使 JUnit 没有这样的选项,您为什么要为此开发自定义代理而不是使用 AspectJ?或者,如果 AspectJ 对您来说太容易并且您想编写更多代码,也许是 ByteBuddy?对于这样一个简单的高级任务,ASM 的级别差不多。这只是一个用于学习目的的游乐场项目吗?
-
@apangin 很抱歉我忘了显示这些代码。现在我已经编辑了这个问题。我只是使用
addTransformer方法注册。但是在日志中找不到BaseTest,说明没有进入transform方法。 -
@kriegaex 实际上它是一个严肃的工具。我使用 ASM 是因为我想做的不仅仅是监控测试执行。其实每个测试方法的执行过程中我都需要记录执行的类,所以我只是顺便用ASM来监控测试实体的开始/结束。
标签: java jvm instrumentation java-bytecode-asm javaagents