6 Stimmen

Wie testet man einen ClassFileTransformer / javaagent?

Ich habe eine ClassFileTransformer für einen Javaagenten mit ASM. Da er einige Bugs hat, möchte ich einen JUnit-Testfall dafür schreiben. Wie kann ich das tun?

Mit Hilfe von Pseudocode dachte ich in etwa so:

// 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());

Die Frage ist nun: Wie lade und transformiere ich das Subjekt manuell und bringe die JVM/Classloader dazu, meine manipulierte Version davon zu verwenden? Oder übersehe ich etwas völlig?

7voto

roesslerj Punkte 2531

Ich habe sie. Man muss eine eigene ClassLoader die mit der Testperson die gleiche Transformation durchführt wie die ClassFileTransformer (z.B. ruft sie an). Und natürlich darf die Subjektklasse noch nicht geladen sein, so dass sie nicht direkt verwendet werden kann. Daher habe ich die Java Reflection API verwendet, um die Methoden der Subjektklasse auszuführen.

In einer separaten Datei:

public static class Subject {
    public void doSomething(){...}
}

Im Test:

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());
}

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X