2012-01-27 3 views
6

Я использую JUnit 4.10 для запуска тестовых наборов, и я применил правило «повторить попытку теста» после замечательных заметок Мэтью Фарвелла в сообщении How to Re-run failed JUnit tests immediately?. Я создал класс «RetryTestRule» со следующим кодом:Как применить JUnit @Rule для всех тестовых примеров в наборе

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

При использовании этого, как правило, внутри тестового примера он прекрасно работает, но это, кажется, не оптимально использовать @Rule обозначения в каждом тестовом случае люкс вместо одной записи в определении сюиты, поэтому после проверки немного, я попробовал новое @ClassRule нотацию в моем классе люкса:

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

Проблема в том, это не работает, как ожидалось: потерпел неудачу испытание не повторено , Кто-нибудь пробовал это и знает решение? Помощь очень ценится!

+0

Возможно, это будет дубликат: http://stackoverflow.com/questions/7639353/how-to-define-junit-method-rule-in-a-suite – pholser

+0

Вы совсем не беспокоитесь о том, что ваш блок тесты прерываются случайным образом? – Tobb

ответ

6

@ClassRule s выполняются один раз в классе, а не один раз по методу. Чтобы что-то выполнялось один раз за метод, вам нужно использовать @Rule, как вы делаете, или следуйте ответам на How to define JUnit method rule in a suite?.

Чтобы повторно использовать существующие правила, вы можете добавить правило в список правил для запуска, используя RunRules класс следующим образом:

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

Это использует пример из приведенного выше ответа. Вероятно, вы могли бы объединить два ответа и для более мелкозернистого управления, создав RetryTestRule, если бы, например, была аннотация для вашего теста.

+0

Большое спасибо за ваш быстрый ответ, Мэтью. Я объединил оба ответа, как вы предложили, и легко создал пользовательский бегун и набор. Затем я добавил @RunWith (MySuite.class) в свой класс и вуаля! Получил автоматическое повторение теста при сбое для всего пакета :) – jbaxenom

+0

Мне что-то не хватает или этот подход (* комбинация обоих ответов *) заставляет тесты запускаться до выполнения '@ClassRule ... ExternalResource .. .. перед тем способ' – Daniel

Смежные вопросы