我想知道如何使用Espresso重新运行失败的测试。我认为从常见的JUnit测试案例来看,它有点复杂,因为您需要在测试开始之前恢复应用中的状态。
我的方法是创建自己的ActivityTestRule,所以我只是从这个类中复制了整个代码,并将其命名为MyActivityTestRule。
在仪器测试的情况下,规则还需要有关我们如何开始活动的信息。我更愿意自己推出它而不是为我做环境。例如:
@Rule
public MyActivityTestRule<ActivityToStartWith> activityRule = new MyActivityTestRule<>(
ActivityToStartWith.class, true, false
);
所以我也在@Before注释方法中启动我的活动:
@Before
public void setUp() throws Exception {
activityRule.launchActivity(new Intent());
}
并在@After注释方法中进行清理:
@After
public void tearDown() throws Exception {
cleanUpDataBaseAfterTest();
returnToStartingActivity(activityRule);
}
这些方法 - setUp(),tearDown()对于在每次测试运行之前/之后调用至关重要 - 以确保测试开始期间的应用程序状态是正确的。
在MyActivityTestRule内部我到目前为止做了一些修改。首先是应用方法的变更:
@Override
public Statement apply(final Statement base, Description description) {
return new ActivityStatement(super.apply(base, description));
}
对我来说这是个未知的事情,因为放在ActivityTestRule中的ActivityStatement具有super.apply方法,因此它还在UiThreadStatement中包装了测试语句:
public class UiThreadStatement extends Statement {
private final Statement mBase;
private final boolean mRunOnUiThread;
public UiThreadStatement(Statement base, boolean runOnUiThread) {
mBase = base;
mRunOnUiThread = runOnUiThread;
}
@Override
public void evaluate() throws Throwable {
if (mRunOnUiThread) {
final AtomicReference<Throwable> exceptionRef = new AtomicReference<>();
getInstrumentation().runOnMainSync(new Runnable() {
public void run() {
try {
mBase.evaluate();
} catch (Throwable throwable) {
exceptionRef.set(throwable);
}
}
});
Throwable throwable = exceptionRef.get();
if (throwable != null) {
throw throwable;
}
} else {
mBase.evaluate();
}
}
}
不管我对我的测试做什么我永远不能创建case mRunOnUiThread boolean为true。如果在我的测试用例中,将出现带有注释@UiThreadTest的测试 - 或者这是我从代码中理解的内容。它永远不会发生,我不会使用任何类似的东西所以我决定忽略这个UiThreadStatement并将MyActivityTestRule更改为:
@Override
public Statement apply(final Statement base, Description description) {
return new ActivityStatement(base);
}
我的测试用例没有任何问题。感谢我留下的所有东西 - 包围mBase.evaluate()的是:
private class ActivityStatement extends Statement {
private final Statement mBase;
public ActivityStatement(Statement base) {
mBase = base;
}
@Override
public void evaluate() throws Throwable {
try {
if (mLaunchActivity) {
mActivity = launchActivity(getActivityIntent());
}
mBase.evaluate();
} finally {
finishActivity();
afterActivityFinished();
}
}
}
一般来说,只有在ActivityTestRule构造函数值为true的第3个参数中设置时,才会调用launchActivity。但我自己在setUp()中启动测试,所以它永远不会发生。
据我所知,mBase.evaluate()在@Test注释方法中运行我的代码。它还会在throwable被抛出期间停止测试用例。这意味着我可以抓住它并重新启动它 - 就像在那里提出的那样: How to Re-run failed JUnit tests immediately?
好吧,我做了类似的事情:
public class ActivityRetryStatement extends Statement {
private final Statement mBase;
private final int MAX_RUNS = 2;
public ActivityRetryStatement(Statement base) {
mBase = base;
}
@Override
public void evaluate() throws Throwable {
Throwable throwable = null;
for (int i = 0; i < MAX_RUNS; i++) {
try {
mBase.evaluate();
// if you reach this lane that means evaluate passed
// and you don't need to do the next run
break;
} catch (Throwable t) {
// save first throwable if occurred
if (throwable == null) {
throwable = t;
}
// my try that didn't work
launchActivity(testInitialIntent);
// I've returned test to starting screen but
// mBase.envaluate() didn't make it run again
// it would be cool now to:
// - invoke @After
// - finish current activity
// - invoke @Before again and start activity
// - mBase.evaluate() should restart @Test on activity started again by @Before
}
}
finishActivity();
afterActivityFinished();
// if 1st try fail but 2nd passes inform me still that there was error
if (throwable != null) {
throw throwable;
}
}
}
因此,catch块中的那些评论是我不知道该怎么做的部分。我尝试在setUp()中使用的intent上执行launchActivity,以便第一次运行测试。但是mBase.evaluate()并没有让它做出反应(测试用例没有再发生) - 没有发生任何事情+我认为它并不能真正拯救我。我在@SetUp中缺少一些启动,它没有被再次调用。我真的想找到一种方法如何正确地重新启动整个测试生命周期@Before @Test @After再次。也许有些人会从代码中调用Instrumentation或TestRunner。
关于如何做到的任何想法?