如何运行 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
我需要收集一些关于我当前应用程序的数据,以便通过检查 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