Java – how to rerun failed tests in Espresso? – Brainstorm
I want to find out how to rerun failed tests using espresso I think from the common JUnit test cases, this is a little complicated because you need to restore the state in the application before the test starts
My method is to create my own activitytestrule, so I just copied the whole code from this class and named it myactivitytestrule
In the case of instrument testing, the rules also need information about how we start the activity I prefer to launch it myself rather than make an environment for me For example:
@Rule public MyActivityTestRule<ActivityToStartWith> activityRule = new MyActivityTestRule<>( ActivityToStartWith.class,true,false );
So I also start my activity in the @ before annotation method:
@Before public void setUp() throws Exception { activityRule.launchActivity(new Intent()); }
And clean it up in the @ after annotation method:
@After public void tearDown() throws Exception { cleanUpDataBaseAftertest(); returnToStartingActivity(activityRule); }
These methods – setUp (), tearDown () -- are the necessary conditions before and after each test run to ensure that the application state is correct during the start of the test.
In myactivitytestrule, I have made some changes so far First, the change of application method comes from:
@Override public Statement apply(final Statement base,Description description) { return new ActivityStatement(super.apply(base,description)); }
This is unknown to me because the activitystatement placed in the activitytestrule has super Apply method, so it also wraps the test statement in 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(); } } }
No matter what I do to my test, I can never create a case mrunonuithread with a Boolean value of true If in my test case, there will be a test with the comment @ uithreadtest - or that's what I understand from the code It will never happen. I don't use anything similar, so I decided to ignore this uithreadstatement and change myactivitytestrule to:
@Override public Statement apply(final Statement base,Description description) { return new ActivityStatement(base); }
There is nothing wrong with my test case Thanks for everything I left – surround mbase The of evaluate() is:
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(); } } }
Typically, launchactivity. Is called only when the constructor value true is set in the third parameter of activitytestrule But I started the test myself in setup (), so it will never happen
As I understand it, mbase Evaluate () runs my code in the @ test annotation method It also stops the test case while throwable is thrown This means that I can grab it and restart it - as suggested there: how to re run failed JUnit tests immediately?
Well, I did something similar:
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; } } }
Therefore, the comments in the catch block are the parts I don't know what to do I tried to execute the launchactivity on the intent used in setup () to run the test for the first time But mbase Evaluate () didn't make it react (the test case didn't happen again) – nothing happened and it won't really save me, I think I'm missing some startup in @ setup. It hasn't been called again I really want to find a way to correctly restart the whole test life cycle @ before @ test @ after again Maybe someone calls Instrumentation or TestRunner. from code.
Any ideas on how to do it?
Solution
The answer is very simple Just make sure you upgrade the espresso test to JUnit 4, and then look at this answer