如何反复运行单元测试+ Espresso?

时间:2016-12-14 17:08:08

标签: android android-espresso android-testing

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

type A struct {
   X string
   Y int
   Z *A
}

3 个答案:

答案 0 :(得分:2)

借助@Be_negative评论,this博文和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;
    }
}

答案 1 :(得分:2)

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

这个测试需要是课堂上唯一的测试,或者更好的是所有的测试方法都需要在课堂上运行10次。

以下是一个例子:

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

通过上述内容,甚至可以使用无参数构造函数来完成它,但我不确定框架作者是否打算这样做,或者将来是否会破坏。

如果您正在实施自己的跑步者,那么您可以让跑步者进行10次测试。如果您正在使用第三方运行程序,那么使用4.7,您可以使用新的@Rule注释并实现MethodRule接口,以便它获取语句并在for循环中执行10次。这种方法目前的缺点是@Before和@After只运行一次。这可能会在JUnit的下一个版本中发生变化(@Before将在@Rule之后运行),但是无论你是在同一个对象实例上行动(参数化运行器都不是这样)。这假设您正在运行该类的任何跑步者正确识别@Rule注释。只有当它委托给JUnit跑步者时才会这样。

如果你使用的是不能识别@Rule注释的自定义运行器,那么你真的不得不编写自己的运行器,它适当地委托给Runner并运行它10次。

请注意,还有其他方法可以解决此问题(例如Theories runner),但它们都需要跑步者。不幸的是,JUnit目前不支持跑步者层。这是一个连锁其他选手的跑步者。

答案 2 :(得分:0)

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