2010-06-21 22 views

Trả lời

61

Nếu bạn chắc chắn thực sự muốn làm điều này: Có thể có một cách tốt hơn, nhưng điều này là tất cả tôi có thể đưa ra ...

Junit4 có một chú thích: @RunWith cho phép bạn ghi đè Runner mặc định cho các bài kiểm tra của bạn.

Trong trường hợp của bạn, bạn muốn tạo một lớp con đặc biệt là BlockJunit4ClassRunner và ghi đè computeTestMethods() để trả lại các thử nghiệm theo thứ tự bạn muốn chúng được thực thi. Ví dụ, chúng ta hãy nói rằng tôi muốn thực hiện các bài kiểm tra của tôi trong thứ tự chữ cái ngược lại:

public class OrderedRunner extends BlockJUnit4ClassRunner { 

    public OrderedRunner(Class klass) throws InitializationError { 
     super(klass); 
    } 

    @Override 
    protected List computeTestMethods() { 
     List list = super.computeTestMethods(); 
     List copy = new ArrayList(list); 
     Collections.sort(copy, new Comparator() { 
      public int compare(FrameworkMethod o1, FrameworkMethod o2) { 
       return o2.getName().compareTo(o1.getName()); 
      } 
     }); 
     return copy; 
    } 
}
@RunWith(OrderedRunner.class) 
public class OrderOfTest { 
    @Test public void testA() { System.out.println("A"); } 
    @Test public void testC() { System.out.println("C"); } 
    @Test public void testB() { System.out.println("B"); } 
}

Chạy thử nghiệm này tạo ra:

C 
B 
A

Đối với trường hợp cụ thể của bạn, bạn sẽ muốn có một so sánh mà có sắp xếp các bài kiểm tra theo tên theo thứ tự bạn muốn chúng được thi hành. (Tôi sẽ đề nghị xác định bộ so sánh sử dụng thứ gì đó như lớp của Google Guava Ordering.explicit("methodName1","methodName2").onResultOf(...); trong đó onResultOf được cung cấp một chức năng chuyển đổi FrameworkMethod thành tên của nó ... mặc dù rõ ràng là bạn được tự do thực hiện theo bất kỳ cách nào bạn muốn.

+0

Cảm ơn bạn đã dành thời gian trả lời Michael này. –

+1

Đó là hữu ích, cảm ơn! BTW, tôi cần phải thực hiện một thay đổi nhỏ để làm cho nó biên dịch - "Comparator mới()" -> "Comparator mới ()" – kc2001

62

Tôi có thể thấy một số lý do để làm điều này, đặc biệt là khi sử dụng JUnit để chạy các kiểm thử chức năng hoặc kiểm tra các đối tượng liên tục, ví dụ, hãy xem xét một đối tượng Article và nó vẫn tồn tại trong một số loại lưu trữ liên tục. Article đối tượng theo nguyên tắc kiểm tra đơn vị "tất cả các thử nghiệm phải được sắp xếp lại và chỉ thử nghiệm một phần cụ thể của chức năng", tôi sẽ có ba thử nghiệm:

  • testInsertArticle()
  • testUpdateArticle()
  • testDeleteArticle()

Tuy nhiên, để có thể kiểm tra chức năng cập nhật, đầu tiên tôi sẽ cần phải chèn bài viết. Để kiểm tra chức năng xóa, tôi cũng sẽ cần chèn một bài viết. Vì vậy, trên thực tế, chức năng chèn đã được kiểm tra cả trong số testUpdateArticle()testDeleteArticle(). Đó là sau đó hấp dẫn để chỉ cần tạo ra một phương pháp thử nghiệm testArticleFunctionality() mà làm tất cả, nhưng các phương pháp như vậy cuối cùng sẽ nhận được rất lớn (và họ sẽ không chỉ kiểm tra một phần chức năng của đối tượng Article).

Điều tương tự cũng xảy ra khi chạy thử nghiệm chức năng chống lại ví dụ như một API an toàn. JUnit cũng rất tốt cho những trường hợp này nếu nó không phải là thứ tự kiểm tra không xác định.

Điều đó nói rằng, tôi đã mở rộng số OrderedRunner của Michael D để sử dụng chú thích để xác định thứ tự kiểm tra, chỉ cần nghĩ rằng tôi nên chia sẻ. Nó có thể được mở rộng hơn nữa, ví dụ bằng cách xác định chính xác các bài kiểm tra mà mỗi bài kiểm tra phụ thuộc vào, nhưng đây là những gì tôi đang sử dụng cho bây giờ.

Đây là cách sử dụng. Nó tránh được nhu cầu đặt tên cho các thử nghiệm như AA_testInsert(), AB_testUpdate(), AC_testDelete(), ..., ZC_testFilter(), v.v.

@RunWith(OrderedRunner.class) 
public class SomethingTest { 
    @Test 
    @Order(order=2) 
    public void testUpdateArticle() { 
     // test update 
    } 

    @Test 
    @Order(order=1) 
    public void testInsertArticle() { 
     // test insert 
    } 

    @Test 
    @Order(order=3) 
    public void testDeleteArticle() { 
     // test delete 
    } 
} 

Không có vấn đề làm thế nào những thử nghiệm được đặt trong tập tin, họ sẽ luôn luôn được chạy như order=1 đầu tiên, order=2 thứ hai và cuối cùng order=3, không có vấn đề nếu bạn chạy chúng từ bên trong Eclipse, sử dụng Ant, hoặc bất kỳ cách nào khác .

Thực hiện sau. Đầu tiên, chú thích Order.

@Retention(RetentionPolicy.RUNTIME) 
public @interface Order { 
    public int order(); 
} 

Sau đó, sửa đổi OrderedRunner.

public class OrderedRunner extends BlockJUnit4ClassRunner { 
    public OrderedRunner(Class<?> klass) throws InitializationError { 
     super(klass); 
    } 

    @Override 
    protected List<FrameworkMethod> computeTestMethods() { 
     List<FrameworkMethod> list = super.computeTestMethods(); 
     Collections.sort(list, new Comparator<FrameworkMethod>() { 
      @Override 
      public int compare(FrameworkMethod f1, FrameworkMethod f2) { 
       Order o1 = f1.getAnnotation(Order.class); 
       Order o2 = f2.getAnnotation(Order.class); 

       if (o1 == null || o2 == null) 
        return -1; 

       return o1.order() - o2.order(); 
      } 
     }); 
     return list; 
    } 
} 
+4

+1 cho thứ tự dựa trên chú thích chứ không phải là chữ cái – Matt

+1

Chính xác những gì tôi muốn tìm . Có thể tốt hơn nếu phương thức chú thích là 'value()' và chỉ viết '@Order (1)' – lyomi

+0

Tôi đã làm theo mã của bạn, nó hoạt động rất tốt, nhưng sau khi nhập cùng một mã vào các trường hợp thử nghiệm có 50 test case I đã có lỗi 'initializationerror0'. Tôi đang sử dụng Kepler với JUnit4.10 – yashhy

1

Nếu bạn muốn chạy thử nghiệm junit theo thứ tự "cũng giống như họ thể hiện trong mã nguồn của bạn", và không muốn sửa đổi mã xét nghiệm của bạn, thấy note của tôi về vấn đề này ở đây:

How to run junit tests in order as they present in your source code

Nhưng thực sự không phải là ý tưởng hay, các thử nghiệm phải độc lập.

25

Từ phiên bản JUnit 4.11 trở đi, có thể ảnh hưởng đến thứ tự thực hiện kiểm tra bằng cách chú thích lớp học của bạn với @FixMethodOrder và chỉ định bất kỳ số nào có sẵn MethodSorters. Xem liên kết this để biết thêm chi tiết.

4

Sử dụng junit 4.11 các new annotation@FixMethodOrder cho phép để thiết lập một trật tự nhất định:

@FixMethodOrder(MethodSorters.NAME_ASCENDING) 
+0

Vì vậy, trong trường hợp của tôi, lý do tôi nhìn vào điều này - giống với áp phích ở trên và đối tượng 'bài viết' của anh ấy - đó là nếu thử nghiệm đầu tiên không làm phiền việc chạy những cái khác, vì chúng đang sử dụng tính năng được thử nghiệm đầu tiên. Để kết thúc những gì tôi muốn là, nếu thử nghiệm đầu tiên thất bại, cho các xét nghiệm còn lại để ném một cái gì đó như 'AssumptionViolatedException' (gây ra các bài kiểm tra được dán nhãn là 'bỏ qua' trong Á hậu cụ thể của tôi, intelliJ). Tôi có thể làm điều này với if-statement & fields, nhưng tôi tự hỏi nếu JUnit có một cơ sở đẹp hơn được xây dựng trong. – Groostav

+0

@Groostav Có 'hàm giả()'/'giả định()' v.v. Bạn có thể có phép thử đầu tiên thiết lập một boolean tĩnh trên lớp thử nghiệm thành 'true' nếu nó vượt qua và sau đó' falseTrue (cờ) 'trong các thử nghiệm khác , ví dụ. Hoặc bạn có thể kiểm tra nó một lần duy nhất trong phương thức '@ Before' (cần một lá cờ khác hoặc cờ ba trạng thái để bỏ qua lần kiểm tra đầu tiên trước khi kiểm tra đầu tiên chạy). –

1

Joscarsson và Michael D mã trong repo github của tôi. Tôi hy vọng họ không quan tâm. Tôi cũng cung cấp phiên bản đặt hàng cho lớp Parameterized. Nó đã được sử dụng làm phụ thuộc maven

<repositories> 
    <repository> 
     <id>git-xxx</id> 
     <url>https://github.com/crsici/OrderedRunnerJunit4.11/raw/master/</url> 
    </repository> 
</repositories> 

<dependency> 
    <groupId>com.sici.org.junit</groupId> 
    <artifactId>ordered-runner</artifactId> 
    <version>0.0.1-RELEASE</version> 
</dependency>