Created
March 31, 2011 20:51
-
-
Save abyx/897229 to your computer and use it in GitHub Desktop.
Simple JUnit rule to make tests retry
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class RetrierTest { | |
private static int count = 0; | |
@Rule public RetryRule rule = new RetryRule(); | |
@Test | |
@Retry | |
public void failsFirst() throws Exception { | |
count++; | |
assertEquals(2, count); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@Retention(RetentionPolicy.RUNTIME) | |
public @interface Retry {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class RetryRule implements MethodRule { | |
@Override public Statement apply(final Statement base, final FrameworkMethod method, Object target) { | |
return new Statement() { | |
@Override public void evaluate() throws Throwable { | |
try { | |
base.evaluate(); | |
} catch (Throwable t) { | |
Retry retry = method.getAnnotation(Retry.class); | |
if (retry != null) { | |
base.evaluate(); | |
} else { | |
throw t; | |
} | |
} | |
} | |
}; | |
} | |
} |
In Kotlin:
RetryRule:
import org.junit.rules.MethodRule
import org.junit.runners.model.FrameworkMethod
import org.junit.runners.model.Statement
class RetryRule : MethodRule {
override fun apply(base: Statement, method: FrameworkMethod, target: Any): Statement {
return object : Statement() {
override fun evaluate() {
try {
base.evaluate()
} catch (t: Throwable) {
val retry = method.getAnnotation(Retry::class.java)
if (retry != null) {
base.evaluate()
} else {
throw t
}
}
}
}
}
}
RetrierTest:
import org.junit.Assert.assertEquals
import org.junit.Rule
import org.junit.Test
class RetrierTest {
companion object {
private var count = 0
}
@get:Rule var rule = RetryRule()
@Test
@Retry
@Throws(Exception::class)
fun failsFirst() {
count++
assertEquals(2, count)
}
}
Retry:
@Retention(AnnotationRetention.RUNTIME)
annotation class Retry
Below code snippet is if you want to retry tests X number.
RetryKotlin.kt
/**
* Retry test rule used to retry test that failed. Retry failed test 3 times
*/
class RetryTestRule(val retryCount: Int = 3) : TestRule {
private val TAG = RetryTestRule::class.java.simpleName
override fun apply(base: Statement, description: Description): Statement {
return statement(base, description)
}
private fun statement(base: Statement, description: Description): Statement {
return object : Statement() {
@Throws(Throwable::class)
override fun evaluate() {
var caughtThrowable: Throwable? = null
// implement retry logic here
for (i in 0 until retryCount) {
try {
base.evaluate()
return
} catch (t: Throwable) {
caughtThrowable = t
Log.e(TAG, description.displayName + ": run " + (i + 1) + " failed")
}
}
Log.e(TAG, description.displayName + ": giving up after " + retryCount + " failures")
throw caughtThrowable!!
}
}
}
}
Add rule to tests class:
@Rule
@JvmField
val mRetryTestRule = RetryTestRule()
You can add retry Rule to Android espresso tests.
not working for me test get failed but it will not retry
error androidTest.RetryRule$1.evaluate(RetryRule.java:16)
junit.framework.AssertionFailedError: expected:<5> but was:<2>
@AndreSand is there a way to adapt your snippet to work on a per-test basis? (instead of a per-test-class basis)
@tomdwp
public class RetryRule implements MethodRule {
private AtomicInteger retryCount;
public RetryRule() {
this(3);
}
public RetryRule(int retries) {
super();
this.retryCount = new AtomicInteger(retries);
}
@Override
public Statement apply(final Statement base, final FrameworkMethod method, Object target) {
return new Statement() {
@Override
public void evaluate() throws Throwable {
Throwable caughtThrowable = null;
while (retryCount.getAndDecrement() > 0) {
try {
base.evaluate();
return;
} catch (Throwable t) {
if (retryCount.get() > 0 &&
method.getAnnotation(Retry.class) != null) {
caughtThrowable = t;
System.err.println(
method.getName() +
": Failed, " +
retryCount.toString() +
"retries remain");
} else {
throw caughtThrowable;
}
}
}
}
};
}
}
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
what if their is a requirement to only retry till count of 3