You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何重试失败的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+,配置步骤:
    1. 在app模块的build.gradle中添加依赖:
      androidTestImplementation 'com.google.testing.platform:android-test-retry:1.0.0'
      
    2. 在测试类或方法上添加注解指定重试次数:
      import com.google.testing.platform.annotation.RetryOnFailure;
      import org.junit.Test;
      
      @RetryOnFailure(maxAttempts = 3)
      public class MyInstrumentedTest {
          @Test
          public void unstableTest() {
              // 测试逻辑
          }
      }
      
    该库会自动捕获失败并触发重试,无需额外CI配置。

方案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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 05:42:53