Using the old JUnit3-style tests in Android, I could do the following to destory and restart an activity:
Instrumentation inst = getInstrumentation();
Activity activity = inst.getActivity();
// do something
activity.finish();
Assert.assertTrue(this.activity.isFinishing());
activity = inst.getActivity();
// assert that activity's state is restored
How can I accomplish the same thing using the new Testing Support Library? I'm fine with using either Espresso and/or UI Automator or any other mechanism provided by the new library.
Update:
I tried the following:
Activity activity = activityTestRule.getActivity();
// do something
activity.finish();
Assert.assertTrue(this.activity.isFinishing());
activity = activityTestRule.getActivity();
// assert that activity's state is restored
However, it appears that ActivityTestRule.getActivity()
does not restart the activity.
As @CommonsWare mentioned, a custom rule is pretty useful. Here's my simple solution (many improvements are possible, but this is just a quick framework that can be built on):
public class ControlledActivityTestRule<T extends Activity> extends ActivityTestRule<T> {
public ControlledActivityTestRule(Class<T> activityClass) {
super(activityClass, false);
}
public ControlledActivityTestRule(Class<T> activityClass, boolean initialTouchMode) {
super(activityClass, initialTouchMode, true);
}
public ControlledActivityTestRule(Class<T> activityClass, boolean initialTouchMode, boolean launchActivity) {
super(activityClass, initialTouchMode, launchActivity);
}
public void finish() {
finishActivity();
}
public void relaunchActivity() {
finishActivity();
launchActivity();
}
public void launchActivity() {
launchActivity(getActivityIntent());
}
}
Note, if you do it like this, this class needs to be in the package android.support.test.rule
to access the package private method ActivityTestRule#finishActivity
. Then in your test case, implement this rule:
@Rule
public ControlledActivityTestRule<TestFountainPreferenceActivity> actRule = new ControlledActivityTestRule<>(TestFountainPreferenceActivity.class);
Then in your individual test case, call actRule.finish()
and actRule.launchActivity()
to kill and restart it. Or you can call actRule.relaunchActivity()
if you don't need to do anything in between killing it and starting it up again. Note, you can pass the third parameter false
to delay starting the activity if you have initial startup, and then call actRule.launchActivity()
to get it going, but you will loose access to some of the built in handles such as #afterActivityLaunched
and #afterActivityFinished()
.
As JCricket and djunod says the way to do it is creating a custom rule. The problem that I faced with their solutions is that the method finishActivity is package protected and you can use it in your custom test rule.
This is my solution:
public class RelaunchActivityRule<T extends Activity> extends ActivityTestRule<T> {
public RelaunchActivityRule(Class<T> activityClass) {
super(activityClass,false);
}
public RelaunchActivityRule(Class<T> activityClass, boolean initialTouchMode) {
super(activityClass, initialTouchMode,true);
}
public RelaunchActivityRule(Class<T> activityClass, boolean initialTouchMode,
boolean launchActivity) {
super(activityClass, initialTouchMode, launchActivity);
}
@Override protected void afterActivityFinished() {
super.afterActivityFinished();
launchActivity(getActivityIntent());
}
}
JCricket's answer worked for me once I added a sleep in there...
package android.support.test.rule;
public class ControlledActivityTestRule<T extends Activity> extends ActivityTestRule<T> {
public ControlledActivityTestRule(Class<T> activityClass) {
super(activityClass, false);
}
public ControlledActivityTestRule(Class<T> activityClass, boolean initialTouchMode) {
super(activityClass, initialTouchMode, true);
}
public ControlledActivityTestRule(Class<T> activityClass, boolean initialTouchMode, boolean launchActivity) {
super(activityClass, initialTouchMode, launchActivity);
}
public void finish() {
finishActivity();
}
public void relaunchActivity(int seconds) {
finishActivity();
sleep(seconds);
launchActivity();
sleep(seconds);
}
public void launchActivity() {
launchActivity(getActivityIntent());
}
public void sleep(int seconds) {
if (seconds > 0) {
try {
Thread.sleep(seconds * 1000);
} catch (Exception ex) {
}
}
}
}
I was then able to do a test with iterations:
@Rule
public ControlledActivityTestRule<MainActivity> mActivityRule = new ControlledActivityTestRule<>(MainActivity.class);
@Test
public void testOAA310() {
int count = 1000;
for (int i = 0; i < count; i++) {
testCaseOAA310();
mActivityRule.relaunchActivity(5);
}
}
void testCaseOAA310() { /* ... blah blah blah... */ }
Try creating a custom rule. Call launchActivity(getActivityIntent())
in afterActivityFinished
method, it will restart the activity after finish.
public class RestartActivityRule<T extends Activity> extends ActivityTestRule<T> {
public RestartActivityRule(Class<T> activityClass) {
super(activityClass,false);
}
public RestartActivityRule(Class<T> activityClass, boolean initialTouchMode) {
super(activityClass, initialTouchMode,true);
}
public RestartActivityRule(Class<T> activityClass, boolean initialTouchMode,
boolean launchActivity) {
super(activityClass, initialTouchMode, launchActivity);
}
@Override protected void afterActivityFinished() {
super.afterActivityFinished();
launchActivity(getActivityIntent());
}
}