2009-11-28 34 views
19

Tôi đang thử nghiệm với các bộ xử lý chú thích java. Tôi có thể viết các bài kiểm tra tích hợp bằng cách sử dụng "JavaCompiler" (trong thực tế, tôi đang sử dụng "hickory" vào lúc này). Tôi có thể chạy quá trình biên dịch và phân tích đầu ra. Vấn đề: một thử nghiệm duy nhất chạy trong khoảng nửa giây ngay cả khi không có bất kỳ mã nào trong bộ xử lý chú thích của tôi. Đây là cách quá dài để sử dụng nó theo phong cách TDD.Làm thế nào để viết các bài kiểm tra đơn vị tự động cho bộ xử lý chú thích java?

Bỏ đi các phụ thuộc có vẻ rất khó đối với tôi (tôi sẽ phải thử toàn bộ gói "javax.lang.model.element"). Có ai đó thành công để viết các bài kiểm tra đơn vị cho một bộ xử lý chú thích (Java 6) không? Nếu không ... thì cách tiếp cận của bạn là gì?

Trả lời

8

Bạn đang mô phỏng đúng API xử lý chú thích (với thư viện mô phỏng như easymock) rất đau. Tôi đã thử cách tiếp cận này và nó đã phá vỡ khá nhanh chóng. Bạn phải thiết lập cho nhiều kỳ vọng cuộc gọi phương thức. Các bài kiểm tra trở nên không thể duy trì được.

A phương pháp thử nghiệm dựa trên trạng thái đã làm việc cho tôi một cách hợp lý. Tôi đã phải thực hiện các phần của javax.lang.model.* API I needed for my tests. (Đó chỉ là < 350 dòng mã.)

Đây là một phần của thử nghiệm để khởi tạo các đối tượng javax.lang.model. Sau khi thiết lập mô hình phải ở trong trạng thái giống như việc thực hiện trình biên dịch Java.

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

Phương thức nhà máy tĩnh được xác định trong lớp Model triển khai lớp javax.lang.model. *. Ví dụ: declaredType. (Tất cả các hoạt động không được hỗ trợ sẽ ném ngoại lệ.)

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

Phần còn lại của bài kiểm tra xác minh hành vi của lớp đang được kiểm tra.

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

Bạn có thể xem source code of the Quickcheck @Samples and @Iterables source code generator tests. (Mã này không tối ưu. Lớp Method có nhiều tham số và lớp Parameter không được kiểm tra trong bài kiểm tra riêng của nó nhưng là một phần của bài kiểm tra Method. Tuy nhiên, nó vẫn minh họa cách tiếp cận này.)

Viel Glück!

0

Tùy chọn là nhóm tất cả các bài kiểm tra trong một lớp. Nửa giây để biên dịch vv không phải là hằng số cho một tập kiểm định nhất định, thời gian thử nghiệm thực tế đối với thử nghiệm là không đủ điều kiện, tôi giả sử.

0

Tôi đã sử dụng http://hg.netbeans.org/core-main/raw-file/default/openide.util.lookup/test/unit/src/org/openide/util/test/AnnotationProcessorTestUtils.java mặc dù điều này được dựa trên java.io.File để đơn giản và do đó có chi phí hiệu suất mà bạn khiếu nại.

Đề xuất của Thomas về chế nhạo toàn bộ môi trường JSR 269 sẽ dẫn đến thử nghiệm đơn vị thuần túy. Thay vào đó, bạn có thể muốn viết thêm bài kiểm tra tích hợp để kiểm tra bộ xử lý của bạn thực sự chạy bên trong javac như thế nào, đảm bảo nó đúng hơn, nhưng chỉ muốn tránh các tệp đĩa. Làm điều này sẽ yêu cầu bạn viết một mẫu JavaFileManager, thật không may là không dễ dàng như nó có vẻ và tôi không có ví dụ tiện dụng, nhưng bạn không cần phải thử những thứ khác như giao diện Element.

35

Đây là câu hỏi cũ, nhưng có vẻ như trạng thái kiểm tra bộ xử lý chú thích đã không nhận được bất kỳ tốt hơn nào, vì vậy chúng tôi đã phát hành Compile Testing hôm nay. Các tài liệu tốt nhất là ở package-info.java, nhưng ý tưởng chung là có API thông thạo để kiểm tra đầu ra biên dịch khi chạy bằng bộ xử lý chú thích.Ví dụ:

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

kiểm tra bộ xử lý tạo tệp phù hợp với GeneratedHelloWorld.java (tệp vàng trên đường dẫn lớp). Bạn cũng có thể kiểm tra xem bộ xử lý có tạo ra kết quả lỗi hay không:

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

Điều này rõ ràng đơn giản hơn nhiều so với chế nhạo và không giống như kiểm tra tích hợp điển hình, tất cả đầu ra được lưu trong bộ nhớ.

0

Tôi đã ở trong tình huống tương tự, vì vậy tôi đã tạo thư viện Avatar. Nó sẽ không cung cấp cho bạn hiệu suất của một thử nghiệm đơn vị thuần túy mà không biên dịch, nhưng nếu được sử dụng đúng cách, bạn sẽ không thấy nhiều tác động đến hiệu năng.

Avatar cho phép bạn viết tệp nguồn, chú thích tệp và chuyển đổi tệp thành các phần tử trong bài kiểm tra đơn vị. Điều này cho phép bạn kiểm tra các phương thức và lớp đơn vị tiêu thụ các đối tượng Element, mà không cần gọi thủ công javac.

Các vấn đề liên quan