2011-07-05 17 views
6

Wprowadziłem ClassFileTransformer dla javaagenta używającego ASM. Ponieważ ma kilka błędów, chcę napisać dla niego test JUnit. Jak mam to zrobic?Jak przetestować ClassFileTransformer/javaagent?

Korzystanie pseudokod Myślałam wzdłuż linii:

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

Teraz pytanie brzmi: Jak mogę ręcznie załadować i przekształcić obiekt i zrobić JVM/ClassLoader używać manipulować wersję tego? Czy mogę całkowicie coś przeoczyć?

Odpowiedz

6

Mam to. Trzeba zaimplementować własny kod ClassLoader, który przeprowadza tę samą transformację z obiektem testowym, co ClassFileTransformer (np. Wywołuje to). Oczywiście klasa przedmiotowa może już nie być załadowana, więc może nie być jej bezpośredniego użycia. Użyłem interfejsu API do refleksji Java, aby wykonać metody klasy przedmiotu.

w oddzielnym pliku:

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

W teście:

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