Tienes razón al burlarse de la API de procesamiento de anotaciones (con una biblioteca simulada como easymock) es doloroso. Probé este enfoque y se rompió bastante rápido. Tienes que configurar muchas expectativas de llamadas de método. Las pruebas se vuelven inmanejables.
A aproximación de prueba basada en estado me ha funcionado bastante bien. Tuve que implementar las partes del javax.lang.model.* API I needed for my tests. (Eso era solo < 350 líneas de código.)
Esta es la parte de una prueba para iniciar los objetos javax.lang.model. Después de la configuración, el modelo debe estar en el mismo estado que la implementación del compilador de Java.
DeclaredType typeArgument = declaredType(classElement("returnTypeName"));
DeclaredType validReturnType = declaredType(interfaceElement(GENERATOR_TYPE_NAME), typeArgument);
TypeParameterElement typeParameter = typeParameterElement();
ExecutableElement methodExecutableElement = Model.methodExecutableElement(name, validReturnType, typeParameter);
Los métodos de fábrica estáticos se definen en la clase Model
la aplicación de la javax.lang.model. * Clases. Por ejemplo, declaredType
. (Todas las operaciones no admitidos lanzar excepciones.)
public static DeclaredType declaredType(final Element element, final TypeMirror... argumentTypes) {
return new DeclaredType(){
@Override public Element asElement() {
return element;
}
@Override public List<? extends TypeMirror> getTypeArguments() {
return Arrays.asList(argumentTypes);
}
@Override public String toString() {
return format("DeclareTypeModel[element=%s, argumentTypes=%s]",
element, Arrays.toString(argumentTypes));
}
@Override public <R, P> R accept(TypeVisitor<R, P> v, P p) {
return v.visitDeclared(this, p);
}
@Override public boolean equals(Object obj) { throw new UnsupportedOperationException(); }
@Override public int hashCode() { throw new UnsupportedOperationException(); }
@Override public TypeKind getKind() { throw new UnsupportedOperationException(); }
@Override public TypeMirror getEnclosingType() { throw new UnsupportedOperationException(); }
};
}
El resto de la prueba verifica el comportamiento de la clase que se está probando.
Method actual = new Method(environment(), methodExecutableElement);
Method expected = new Method(..);
assertEquals(expected, actual);
Puede echar un vistazo a source code of the Quickcheck @Samples and @Iterables source code generator tests. (El código aún no es óptimo. La clase Method tiene muchos parámetros y la clase Parameter no se prueba en su propia prueba sino como parte de la prueba Method. Sin embargo, debe ilustrar el enfoque).
Viel Glück!