2016-12-14 68 views
1

我需要收集我当前的应用程序的一些数据,以便通过检查活动启动期间的平均经过时间来分析性能速度。我想运行一个测试电池,活动开始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() { 
    } 
} 
+1

http://stackoverflow.com/q/1492856/4879701包含少数关于如何多次运行相同的junit测试的解决方案。 –

+0

我确实尝试了其中的大部分,但都失败了:当它试图重复测试时,它无法启动意图,并因超时而失败。这是Espresso生命周期的某种方式。 –

+1

啊,这可能是因为测试规则。只需向launchActivity()提供false布尔值并从测试中手动启动 –

回答

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; 
    } 
} 
+0

我想知道,如果不是按回来,你可以做'mActivityRule.getActivity()。finish()' –

+0

不,我测试过了,这不起作用 –

0

要做到这一点,最简单的方法就是将测试作为参数化测试运行(用@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注释,那么您确实需要编写自己的运行程序,该运行程序正确地委派给该运行程序并运行它10次。

请注意,还有其他方法可能可以解决此问题(如Theories跑步者),但他们都需要跑步者。不幸的是,JUnit目前不支持多层跑步者。这是一个与其他跑步者联系在一起的跑步者。