如何运行 unit test + Espresso 反复?

How to run unit test + Espresso repeatedly?

我需要收集一些关于我当前应用程序的数据,以便通过检查 Activity 启动期间的平均运行时间来分析性能速度。我想 运行 测试电池,其中 activity 启动了 10、100、1000 和 5000 次。对于每个测试,它应该保持打开状态至少 10 秒(收集异步发生的所有数据所需的时间)。我想要的正是这种行为,而不必编写这么多方法:

@RunWith(AndroidJUnit4.class)
@LargeTest
public class TestStreamLoadingPerformance {

    private static final long TIME_OUT = 2;
    private static final long WAITING_TIME = 10000;

    @Rule
    public ActivityTestRule mActivityRule = new ActivityTestRule(HomepageActivity.class);

    private ElapsedTimeIdlingResource mIdleRes = new ElapsedTimeIdlingResource(WAITING_TIME);


    @Before
    public void setUp() {
        IdlingPolicies.setMasterPolicyTimeout(TIME_OUT, TimeUnit.HOURS);
        IdlingPolicies.setIdlingResourceTimeout(TIME_OUT, TimeUnit.HOURS);
        Espresso.registerIdlingResources(mIdleRes);
    }

    @After
    public void tearDown() {
        Espresso.unregisterIdlingResources(mIdleRes);
    }

    @Test
    public void test01() {
    }

    @Test
    public void test02() {
    }

    @Test
    public void test03() {
    }

    @Test
    public void test04() {
    }

    @Test
    public void test05() {
    }

    @Test
    public void test06() {
    }

    @Test
    public void test07() {
    }

    @Test
    public void test08() {
    }

    @Test
    public void test09() {
    }
}

@Be_negative comments, this blog post and this 回答的帮助下,我能够使用以下代码解决问题:

@RunWith(AndroidJUnit4.class)
@LargeTest
public class TestStreamLoadingPerformance {

    @Rule
    public ActivityTestRule mActivityRule = new ActivityTestRule(HomepageActivity.class, false, false);
    @Rule
    public RepeatRule mRepeatRule = new RepeatRule();


    @After
    public void tearDown() {
        closeActivity();
    }

    private void closeActivity() {
        final int N = 10;
        try {
            for (int i = 0; i < N; i++) {
                Espresso.pressBack();
            }
        } catch (NoActivityResumedException e) {
            Log.e(TestStreamLoadingPerformance.class.getSimpleName(), "Unable to close activities", e);
        }
    }

    @Test
    @RepeatRule.Repeat(times = 10)
    public void collectData() {
        mActivityRule.launchActivity(null);
    }
}

import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

public class RepeatRule implements TestRule {
    @Retention(RetentionPolicy.RUNTIME)
    @Target({
            java.lang.annotation.ElementType.METHOD
    })
    public @interface Repeat {
        public abstract int times();
    }

    private static class RepeatStatement extends Statement {

        private final int times;
        private final Statement statement;

        private RepeatStatement(int times, Statement statement) {
            this.times = times;
            this.statement = statement;
        }

        @Override
        public void evaluate() throws Throwable {
            for (int i = 0; i < times; i++) {
                statement.evaluate();
            }
        }
    }

    @Override
    public Statement apply(Statement statement, Description description) {
        Statement result = statement;
        Repeat repeat = description.getAnnotation(Repeat.class);
        if (repeat != null) {
            int times = repeat.times();
            result = new RepeatStatement(times, statement);
        }
        return result;
    }
}

最简单的(因为需要最少的新代码)方法是 运行 将测试作为参数化测试(用 @RunWith(Parameterized.class) 注释并添加方法提供 10 个空参数)。这样框架将 运行 测试 10 次。

这个测试需要是 class 中的唯一测试,或者更好的是所有测试方法应该需要 运行 10 次 class.

这是一个例子:

@RunWith(Parameterized.class)
public class RunTenTimes {
    @Parameterized.Parameters
    public static List<Object[]> data() {
        return Arrays.asList(new Object[10][0]);
    }

    public RunTenTimes() {
    }

    @Test
    public void runsTenTimes() {
        System.out.println("run");
    }
}

根据以上内容,甚至可以使用无参数构造函数来实现,但我不确定框架作者是否有意这样做,或者将来是否会中断。

如果您正在实施自己的 运行ner,那么您可以让 运行ner 运行 测试 10 次。如果您使用的是第三方 运行ner,那么在 4.7 中,您可以使用新的 @Rule 注释并实现 MethodRule 接口,以便它获取语句并在 for 循环中执行 10 次。这种方法目前的缺点是@Before 和@After 只得到一次运行。这可能会在 JUnit 的下一个版本中发生变化(@Before 将在 @Rule 之后 运行),但是无论您将对对象的同一实例进行操作(参数化 [ 并非如此) =30=]纳)。这假设无论您 运行 使用 运行 与 class 正确识别 @Rule 注释。仅当它委托给 JUnit 运行ners.

时才会出现这种情况

如果您是 运行 自定义 运行 不识别 @Rule 注释的 ner,那么您真的不得不编写自己的 运行 适当委托的 ner给那个跑步者 运行 10 次。

请注意,还有其他方法可以解决此问题(例如理论 运行ner),但它们都需要 运行ner。不幸的是,JUnit 目前不支持 运行 层。那是一个 运行ner 链接其他 运行ners。

我有一个非常相似的问题,因此我创建了一个库来多次测试 运行 Android UI。可能对您有用:https://github.com/stepstone-tech/AndroidTestXRunner