如何测试ClassFileTransformer/javaagent?

如何测试ClassFileTransformer/javaagent?,java,instrumentation,javaagents,Java,Instrumentation,Javaagents,我使用ASM为javaagent实现了一个ClassFileTransformer。因为它有一些bug,我想为它编写一个JUnit测试用例。我该怎么做 使用伪代码,我的思路如下: // Have a test class as subject public static class Subject { public void doSomething(){...} } // Manually load and transform the subject ...? // Normally exe

我使用ASM为javaagent实现了一个
ClassFileTransformer
。因为它有一些bug,我想为它编写一个JUnit测试用例。我该怎么做

使用伪代码,我的思路如下:

// Have a test class as subject
public static class Subject {
  public void doSomething(){...}
}
// Manually load and transform the subject
...?
// Normally execute some now transformed methods of the subject
new Subject().doSomething();
// Check the result of the call (i.e. whether the correct attached methods were called)
Assert.assertTrue(MyClassFileTransformer.wasCalled());

现在的问题是:如何手动加载和转换主题,并使JVM/Classloader使用我的操纵版本?还是我完全错过了什么?我明白了。需要实现自己的
类加载器
,该加载器对测试主题进行与
类文件转换器
相同的转换(例如调用它)。当然,subject类可能还没有被加载,因此可能没有直接使用它。因此,我使用Java反射API来执行subject类的方法

在单独的文件中:

public static class Subject {
    public void doSomething(){...}
}
在测试中:

private static class TransformingClassLoader extends ClassLoader {

    private final String className;

    public TransformingClassLoader(String className) {
        super();
        this.className = className;
    }

    @Override
    public Class<?> loadClass(String name) throws ClassNotFoundException {
        if (name.equals(className)) {
            byte[] byteBuffer = instrumentByteCode(fullyQualifiedSubjectClass);
            return defineClass(className, byteBuffer, 0, byteBuffer.length);
        }
        return super.loadClass(name);
    }
}

@Test
public void testSubject(){
    ClassLoader classLoader = new TransformingClassLoader(fullyQualifiedSubjectClass);
    Class<?> subjectClass = classLoader.loadClass(fullyQualifiedSubjectClass);
    Constructor<?> constructor = subjectClass.getConstructor();
    Object subject = constructor.newInstance();
    Method doSomething = subjectClass.getMethod("doSomething");
    doSomething.invoke(subject);
    Assert.assertTrue(MyClassFileTransformer.wasCalled());
}
私有静态类转换ClassLoader扩展ClassLoader{
私有最终字符串类名;
公共转换类加载器(字符串类名称){
超级();
this.className=className;
}
@凌驾
公共类loadClass(字符串名称)引发ClassNotFoundException{
if(name.equals(className)){
byte[]byteBuffer=仪表字节码(fullyQualifiedSubjectClass);
返回defineClass(className,byteBuffer,0,byteBuffer.length);
}
返回super.loadClass(名称);
}
}
@试验
public void testSubject(){
ClassLoader ClassLoader=新转换ClassLoader(fullyQualifiedSubjectClass);
Class subjectClass=classLoader.loadClass(fullyQualifiedSubjectClass);
构造函数=subjectClass.getConstructor();
Object subject=constructor.newInstance();
方法doSomething=subjectClass.getMethod(“doSomething”);
调用(主题);
Assert.assertTrue(MyClassFileTransformer.wasCalled());
}