2012-01-27 31 views
6

Tôi đang sử dụng JUnit 4.10 để chạy bộ thử nghiệm và tôi đã thực hiện quy tắc "thử lại không thành công" sau ghi chú tuyệt vời của Matthew Farwell trong bài đăng How to Re-run failed JUnit tests immediately?. Tôi tạo ra một lớp "RetryTestRule" với đoạn mã sau:Làm thế nào để áp dụng một JUnit @Rule cho tất cả các trường hợp thử nghiệm trong một bộ

public class RetryTestRule implements TestRule { 

    private final int retryCount; 

    public RetryTestRule(int retryCount) { 
    this.retryCount = retryCount; 
    } 

    @Override 
    public Statement apply(Statement base, Description description) { 
    return statement(base, description); 
    } 

    private Statement statement(final Statement base, final Description description) { 
    return new Statement() { 
     @Override 
     public void evaluate() throws Throwable { 
     Throwable caughtThrowable = null; 

     // retry logic 
     for (int i = 0; i < retryCount; i++) { 
      try { 
      base.evaluate(); 
      return; 
      } catch (Throwable t) { 
      caughtThrowable = t; 
      System.err.println(description.getDisplayName() + ": run " + (i + 1) + "  failed"); 
      } 
     } 
     System.err.println(description.getDisplayName() + ": Giving up after " + retryCount 
      + " failures"); 
     throw caughtThrowable; 
     } 
    }; 
    } 
} 

Khi sử dụng này như một quy luật bên trong một trường hợp thử nghiệm nó hoạt động hoàn hảo, nhưng có vẻ như không tối ưu để sử dụng các ký hiệu @Rule trong mọi trường hợp thử nghiệm của một bộ thay vì một ký hiệu duy nhất trong định nghĩa Suite, vì vậy sau khi kiểm tra một chút tôi đã thử các ký hiệu @ClassRule mới trong lớp Suite của tôi:

@RunWith(Suite.class) 
@SuiteClasses({ 
    UserRegistrationTest.class, 
    WebLoginTest.class 
}) 
public class UserSuite {  
    @ClassRule 
    public static RetryTestRule retry = new RetryTestRule(2); 
} 

vấn đề là điều này không làm việc như mong đợi: thất bại kiểm tra không được thử lại . Có ai đã thử điều này và biết một giải pháp? Giúp đỡ được nhiều đánh giá cao!

+0

Có thể trùng lặp: http://stackoverflow.com/questions/7639353/how-to-define-junit-method-rule-in-a-suite – pholser

+0

Bạn hoàn toàn không thấy đơn vị của mình lo lắng kiểm tra thất bại một cách ngẫu nhiên? – Tobb

Trả lời

6

@ClassRule s được thực hiện một lần cho mỗi lớp, không một lần cho mỗi phương thức. Để có điều gì đó được thực thi một lần cho mỗi phương thức, bạn cần sử dụng @Rule như bạn đang làm hoặc làm theo câu trả lời cho How to define JUnit method rule in a suite?.

Để sử dụng lại quy tắc hiện tại của bạn, bạn có thể thêm các quy tắc vào danh sách các quy tắc để chạy, sử dụng lớp RunRules như sau:

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

    @Override 
    protected void runChild(final FrameworkMethod method, RunNotifier notifier) { 
     Description description= describeChild(method); 
     if (method.getAnnotation(Ignore.class) != null) { 
      notifier.fireTestIgnored(description); 
     } else { 
      RunRules runRules = new RunRules(methodBlock(method), Arrays.asList(new TestRule[]{new RetryTestRule(3)}), description); 
      runLeaf(runRules, description, notifier); 
     } 
    } 
} 

này được sử dụng ví dụ từ câu trả lời ở trên. Bạn cũng có thể kết hợp hai câu trả lời để kiểm soát tốt hơn, tạo ra một RetryTestRule nếu có một chú thích trong bài kiểm tra của bạn chẳng hạn.

+0

Cảm ơn bạn rất nhiều vì câu trả lời nhanh của bạn, Matthew. Tôi kết hợp cả hai câu trả lời như bạn đã đề xuất và dễ dàng tạo ra một Á hậu và bộ tùy chỉnh. Sau đó, tôi đã thêm @RunWith (MySuite.class) vào lớp học của tôi và voilà! Có thử nghiệm tự động thử lại trên thất bại cho toàn bộ bộ :) – jbaxenom

+0

Tôi đang thiếu một cái gì đó hoặc phương pháp này (* kết hợp cả hai câu trả lời *) làm cho các thử nghiệm chạy trước khi thực thi '@ClassRule ... ExternalResource .. .. trước phương thức' – Daniel

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