如何重试失败的Android Instrumented Tests?求可行实现方案
可行的Android Instrumented Tests重试方案
方案1:Jenkins脚本精准重试失败用例
避免使用clean命令(会重新执行所有测试,浪费资源),通过Gradle的--tests参数定向重试失败用例,步骤如下:
- 第一步:执行完整插桩测试,生成测试报告
./gradlew app:connectedVariantNameAndroidTest - 第二步:从测试报告(默认路径
app/build/reports/androidTests/connected/下的XML文件)中提取失败测试的类/方法名,可通过shell脚本过滤:FAILURES=$(grep -r "testcase" app/build/reports/androidTests/connected/ | grep -E "status=\"failed\"" | awk -F'name="' '{print $2}' | awk -F'"' '{print $1}') - 第三步:若存在失败用例,执行重试命令:
注:若失败用例数量较多,需调整参数格式,用逗号分隔或多次指定if [ -n "$FAILURES" ]; then ./gradlew app:connectedVariantNameAndroidTest --tests "$FAILURES" fi--tests。
方案2:使用兼容Java 11的重试插件
替换Gordon插件,改用官方支持的兼容库:
- Android Test Retry Library:Google官方推出,支持JUnit 4/JUnit 5,兼容Java 8+,配置步骤:
- 在app模块的
build.gradle中添加依赖:androidTestImplementation 'com.google.testing.platform:android-test-retry:1.0.0' - 在测试类或方法上添加注解指定重试次数:
import com.google.testing.platform.annotation.RetryOnFailure; import org.junit.Test; @RetryOnFailure(maxAttempts = 3) public class MyInstrumentedTest { @Test public void unstableTest() { // 测试逻辑 } }
- 在app模块的
方案3:修复代码实现的重试逻辑(JUnit 4/JUnit 5)
若之前的代码未触发重试,通常是规则/扩展配置错误,以下是正确实现:
JUnit 4 自定义TestRule
import org.junit.rules.TestRule; import org.junit.runner.Description; import org.junit.runners.model.Statement; public class RetryRule implements TestRule { private final int retryCount; public RetryRule(int retryCount) { this.retryCount = retryCount; } @Override public Statement apply(Statement base, Description description) { return new Statement() { @Override public void evaluate() throws Throwable { Throwable lastException = null; for (int i = 0; i < retryCount; i++) { try { base.evaluate(); return; // 测试成功,终止重试 } catch (Throwable t) { lastException = t; System.err.println("测试失败,重试第 " + (i+1) + " 次: " + description.getDisplayName()); } } throw lastException; // 重试耗尽,抛出最后一次异常 } }; } }
在测试类中应用规则:
import org.junit.Rule; import org.junit.Test; public class MyInstrumentedTest { @Rule public RetryRule retryRule = new RetryRule(3); @Test public void unstableTest() { // 测试逻辑 } }
JUnit 5 自定义Extension
import org.junit.jupiter.api.extension.ExtensionContext; import org.junit.jupiter.api.extension.TestExecutionExceptionHandler; import java.util.concurrent.atomic.AtomicInteger; public class RetryExtension implements TestExecutionExceptionHandler { private final int maxAttempts = 3; @Override public void handleTestExecutionException(ExtensionContext context, Throwable throwable) throws Throwable { AtomicInteger attempt = context.getStore(ExtensionContext.Namespace.GLOBAL) .getOrComputeIfAbsent(context.getUniqueId(), key -> new AtomicInteger(0)); if (attempt.incrementAndGet() < maxAttempts) { System.err.println("测试失败,重试第 " + attempt.get() + " 次: " + context.getDisplayName()); return; // 不抛出异常,触发重试 } throw throwable; // 重试耗尽,抛出异常 } }
在测试类中添加注解:
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @ExtendWith(RetryExtension.class) public class MyInstrumentedTest { @Test public void unstableTest() { // 测试逻辑 } }
注:JUnit 5测试需确保使用org.junit.jupiter.api包下的@Test注解,而非JUnit 4的注解。
内容的提问来源于stack exchange,提问作者Zhou Haibo
相关产品推荐
相关产品推荐

