2016-08-03 13 views
2

Ich schreibe eine Bibliothek, die auf der AbstractProcessor Klasse basiert, da ich eine großartige Bibliothek schreiben möchte, möchte ich auch eine gute Berichterstattung haben. Da der Präprozessor zur Kompilierzeit arbeitet, bin ich mir nicht sicher, wie ich diesen Code testen soll.Testen von AbstractProcessor (Javas Annotationshandling zur Kompilierzeit)

Ich habe einige Testszenarien im Auge, wo der Build fehlschlagen sollte. Wie kann ich das testen? Muss ich Gradle ausführen und den Exit-Code prüfen? Gibt es eine saubere Möglichkeit zu überprüfen, ob der Build aufgrund einer erwarteten Ursache fehlschlägt, oder muss ich auch einen Parser schreiben? Das wäre IMHO ein riesiger Overhead nur für eine gute Abdeckung.

Für diejenigen von Ihnen, die ein Beispiel benötigen:

@SupportedAnnotationTypes("eu.rekisoft.java.preprocessor.Decorator") 
@SupportedSourceVersion(SourceVersion.RELEASE_7) 
public class ExamplePreprocessor extends AbstractProcessor { 

    public ExamplePreprocessor() { 
     super(); 
    } 

    @Override 
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { 
     for(Element elem : roundEnv.getElementsAnnotatedWith(Decorator.class)) { 
      Method method = Method.from((ExecutableElement)elem); 
      if(!method.matchesTypes(String.class, StringBuilder.class)) { 
       processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "No! " + elem + " has the wrong args!"); 
      } else { 
       processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, "Yey " + elem + " this is fine!"); 
      } 
     } 
     return true; // no further processing of this annotation type 
    } 
} 

Und hier ist eine Klasse, die kompiliert kann nicht:

public class AnnotationedExample { 
    @Decorator 
    public int breakBuild() { 
     return -1; 
    } 

    @Decorator 
    public String willCompile(StringBuilder sb) { 
     return null; 
    } 
} 

Und schließlich die langweilige Anmerkung:

@Retention(RetentionPolicy.SOURCE) 
@Target(ElementType.METHOD) 
public @interface Decorator { 
} 

Sie können auch das Projekt unter GitHub auschecken, Sie müssen nur das Projekt auschecken und 01 ausführen. Möglicherweise müssen Sie die fehlende x-Berechtigung für das Skript unter Linux und Mac beheben.

+0

Bitte teilen Sie Ihren Code und die Testszenarien, die Sie bisher geschrieben haben. Was ist los mit ihnen? –

+0

Frage mich nur, weißt du, wovon ich spreche? Es ist ein hochkomplexes Thema und wenn Sie damit vertraut sind, sollte das abstrakte Niveau meiner Frage in Ordnung sein. Ich kann jedoch ein Beispiel hinzufügen, wenn dies für Sie klarer wird. – rekire

+0

@RobertColumbia hier ist ein einfaches Beispielprojekt, das nicht wie beabsichtigt kompilieren kann: https://github.com/rekire/AnnotationTesting Sie müssen nur das Projekt auschecken und 'grodlew cJ' ausführen, wenn Sie Linux verwenden, müssen Sie das reparieren fehlende x-Berechtigung des Skripts – rekire

Antwort

1

Dieses Problem wurde von früheren Teams gelöst, die Compiler und Annotationsprozessoren geschrieben haben, sodass Sie ihre Lösungen erneut verwenden konnten.

Das Javac-Team verwendet ein Tool mit der Bezeichnung jtreg. Zum Beispiel ist hier eine jtreg test, die eine Quelldatei 6 Mal mit verschiedenen Befehlszeilenargumenten kompiliert, die jeweils einen anderen expected compiler output angibt.

Das Team Checker Framework entwickelte ein Testframework speziell für Annotationsprozessoren. Hier ist ein test case mit diesem Framework, wo spezielle //:: Kommentare die Zeilen angeben, wo der Annotationsprozessor voraussichtlich a warning oder an error ausgeben wird.

+0

Ich versuche, diese jtreg Bibliothek zu verwenden, aber ich verstehe nicht wirklich, wie man es benutzt. Ich werde versuchen, jtreg innerhalb Gradle zu tunen und für jetzt weiß ich, dass ich 'java -DProgram = jtreg -jar/tmp/jtreg/lib/jtreg.jar' laufen lassen kann, aber welche args muss ich anwenden? Wie startet dieser @ Compile-Kommentar einen neuen Kompiliervorgang? Ich verstehe es überhaupt nicht. – rekire

+0

Okay, ich denke, ich habe es jetzt geschafft, aber meine Referenzdatei stimmt nicht überein. Wie finde ich das genaue Format der Datei heraus? Nur die erwartete Fehlerausgabe? – rekire

+0

Ja, jtreg erfordert, dass die Compiler-Ausgabe der Zieldatei entspricht. jtreg versucht nicht, die Ausgabe clever zu analysieren.Für die Ausführung von jtreg schlage ich vor, die jtreg-Dokumentation zu sehen. – mernst

1

Google hat eine sehr gute API zum Testen der Kompilierung. (https://github.com/google/compile-testing). Hier ist ein Beispiel, um zu testen, ob eine .java-Datei mit einem Prozessor kompiliert wird, der junit verwendet.

package org.coffeebag.processor; 

import com.google.testing.compile.JavaFileObjects; 
import com.google.testing.compile.JavaSourceSubjectFactory; 
import org.junit.Test; 

import java.io.File; 
import java.net.MalformedURLException; 

import static org.truth0.Truth.ASSERT; 

public class ExampleTest { 

    @Test 
    public void EmptyClassCompiles() throws MalformedURLException { 
     final MyProcessor processor = MyProcessor.testMode(); 
     File source = new File("path/to/test/file.java"); 
     ASSERT.about(JavaSourceSubjectFactory.javaSource()) 
       .that(JavaFileObjects.forResource(source.toURI().toURL())) 
       .processedWith(processor) 
       .compilesWithoutError(); 
    } 
} 
Verwandte Themen