2009-11-28 69 views
19

我正在嘗試使用java註釋處理器。我能夠使用「JavaCompiler」編寫集成測試(實際上我現在使用「hickory」)。我可以運行編譯過程並分析輸出。問題:即使在我的註釋處理器中沒有任何代碼,單個測試仍可運行大約半秒鐘。在TDD風格中使用它太長了。 (我將不得不嘲笑整個「javax.lang.model.element」包)。讓某人成功爲註釋處理器(Java 6)編寫單元測試?如果不是......你會怎麼做?如何爲java註釋處理器編寫自動化單元測試?

回答

8

你是對的嘲笑註解處理API(帶有像easymock這樣的模擬庫)是痛苦的。我嘗試了這種方法,並且很快就崩潰了。您必須設置許多方法調用期望。測試變得不可維護。

A 基於狀態的測試方法合理地爲我工作。我必須執行javax.lang.model.* API I needed for my tests的部分。 (這只是< 350行代碼)。

這是啓動javax.lang.model對象的測試的一部分。在設置之後,模型應該與Java編譯器實現處於相同的狀態。

DeclaredType typeArgument = declaredType(classElement("returnTypeName")); 
DeclaredType validReturnType = declaredType(interfaceElement(GENERATOR_TYPE_NAME), typeArgument); 
TypeParameterElement typeParameter = typeParameterElement(); 
ExecutableElement methodExecutableElement = Model.methodExecutableElement(name, validReturnType, typeParameter); 

的靜態工廠方法在實施javax.lang.model類Model定義。*類。例如declaredType。 (所有不支持的操作會拋出異常。)

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

測試的其餘部分驗證被測類的行爲。

Method actual = new Method(environment(), methodExecutableElement); 
Method expected = new Method(..); 
assertEquals(expected, actual); 

你可以看看source code of the Quickcheck @Samples and @Iterables source code generator tests。 (代碼還不是最優的,Method類有許多參數,Parameter類沒有在自己的測試中測試過,但作爲Method測試的一部分,它應該說明這個方法。)

VielGlück!

0

一個選項是將所有測試捆綁在一個類中。對於給定的一組測試,編譯等等的時間只有半秒,而測試的實際測試時間是可以接受的,我假設。

0

爲了簡單起見,我已經使用了http://hg.netbeans.org/core-main/raw-file/default/openide.util.lookup/test/unit/src/org/openide/util/test/AnnotationProcessorTestUtils.java,儘管這是基於java.io.File,因此您的抱怨會帶來性能開銷。

托馬斯關於嘲笑整個JSR 269環境的建議將導致純粹的單元測試。您可能更想寫更多的集成測試,它會檢查處理器在javac中的實際運行情況,從而更確保它是正確的,但僅僅希望避免磁盤文件。這樣做需要你編寫一個模擬JavaFileManager,這不幸並不像看起來那麼簡單,我沒有任何方便的例子,但你不應該嘲笑其他的東西,如Element接口。

35

這是一個古老的問題,但似乎註解處理器測試的狀態沒有得到任何改善,所以我們今天發佈了Compile Testing。最好的文檔在package-info.java,但總體思路是有一個流暢的API用於在使用註釋處理器運行時測試編譯輸出。例如,該處理器生成一個匹配GeneratedHelloWorld.java(金色文件中的類路徑上)的文件

ASSERT.about(javaSource()) 
    .that(JavaFileObjects.forResource("HelloWorld.java")) 
    .processedWith(new MyAnnotationProcessor()) 
    .compilesWithoutError() 
    .and().generatesSources(JavaFileObjects.forResource("GeneratedHelloWorld.java")); 

測試。您也可以測試處理器產生錯誤輸出:

JavaFileObject fileObject = JavaFileObjects.forResource("HelloWorld.java"); 
ASSERT.about(javaSource()) 
    .that(fileObject) 
    .processedWith(new NoHelloWorld()) 
    .failsToCompile() 
    .withErrorContaining("No types named HelloWorld!").in(fileObject).onLine(23).atColumn(5); 

這顯然比嘲諷,不像典型的集成測試簡單了很多,所有的輸出都存儲在內存中。

0

我處於類似的情況,所以我創建了Avatar庫。它不會給你一個沒有編譯的純單元測試的性能,但如果使用得當,你不應該看到太多的性能問題。

頭像可讓您編寫源文件,對其進行註釋並將其轉換爲單元測試中的元素。這使您可以單元測試消耗Element對象的方法和類,而無需手動調用javac。