How to apply JUnit @Rule to all test cases in a set

I use JUnit 4.10 to run test suites, and I applied the "retry test" rule after Matthew Farwell's remarks on "How to re-run unsuccessful JUnit tests"? message. I created the "RetryTestRule" class with the following code:

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

When using this, as a rule, in a test case it works fine, but it seems impractical to use the @Rule notation in each test case package instead of one notation in the Suite definition, so after checking the bits, I tried the new @ClassRule notation in the Suite class:

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

The problem is that this does not work properly: failed tests do not repeat. Has anyone tried this and know a solution? Help is much appreciated!

+6
source share
1 answer

@ClassRule are executed once for each class, not once for each method. For something to be executed once for a method, you need to use @Rule , how do you do it, or follow the answer How to define a rule of a JUnit method in a package? .

To reuse an existing rule, you can add the rule to the list of rules to run using the RunRules class as follows:

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

This is the example above. You could probably combine the two answers for finer-grained control by creating a RetryTestRule if, for example, there was an annotation for your test.

+6
source

Source: https://habr.com/ru/post/907028/


All Articles