I want to write test for recreating activity. Performing rotation is optional.
I want the test to be written in up-to-date version of testing framework "blessed" by Google. I am new to writing tests, so I want to learn basic, main-stream, well supported tools. Any 3rd party testing frameworks will be fine when I grasp basics. And since I want to test very basic, frequently occuring scenario, basic tool should suffice, right?
Minimal test code:
public class MainActivity extends AppCompatActivity {
static int creationCounter = 0;
Integer instanceId;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
++creationCounter;
instanceId = new Integer(creationCounter);
Log.d("TEST", "creating activity " + this + ", has id " + instanceId);
}
}
And testing class:
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
@Rule
public ActivityTestRule<MainActivity> mActivityTestRule = new ActivityTestRule<>(MainActivity.class);
@Test
public void useAppContext() throws Exception {
MainActivity activity1 = mActivityTestRule.getActivity();
int act1 = activity1.instanceId.intValue();
int counter1 = MainActivity.creationCounter;
assertEquals(1, counter1);
assertEquals(1, act1);
Log.d("TEST", "requesting rotation");
// method 1
activity1.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
// method 2 //https://gist.github.com/nbarraille/03e8910dc1d415ed9740#file-orientationchangeaction-java
// onView(isRoot()).perform(orientationLandscape());
getInstrumentation().waitForIdleSync(); // I thought this should suffice
// How to do this?
//somehowRefreshActivityInstanceInsideTestRule();
MainActivity activity2 = mActivityTestRule.getActivity();
int act2 = activity2.instanceId.intValue();
int counter2 = MainActivity.creationCounter;
Log.d("TEST", "newly acquired activity " + activity2 + " has id " + act2 + "/" + counter2);
assertEquals(2, counter2);
assertEquals(2, act2);
}
}
Above code (either method1 or 2) gives logcat:
D/ActivityTestRule: Launching activity example.com.rotationtest.MainActivity
D/TEST: creating activity example.com.rotationtest.MainActivity@47404a3, has id 1
D/TEST: requesting rotation
D/TEST: creating activity example.com.rotationtest.MainActivity@169887e, has id 2
D/TEST: newly acquired activity example.com.rotationtest.MainActivity@47404a3 has id 1/2
I/TestRunner: failed: useAppContext(example.com.rotationtest.ExampleInstrumentedTest)
I/TestRunner: ----- begin exception -----
I/TestRunner: java.lang.AssertionError: expected:<2> but was:<1>
My diagnosis, correct me if I'm wrong:
- activity1.setRequestedOrientation causes creation of new activity in other thread. I HOPE it would receive proper bundle
- getInstrumentation().waitForIdleSync(); causes test to wait until the new activity is created
- mActivityTestRule.getActivity(); still returns old activity instance.
- I need some way to refresh activity instance held inside test rule, release previously held one.
I found answer with older version of test framework: Instrumentation test for Android - How to receive new Activity after orientation change?
mActivity.setRequestedOrientation(
ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
mActivity.finish();
setActivity(null);
mActivity = getActivity();
getInstrumentation().waitForIdleSync();
But I don't know how to translate it into new version.
EDIT:
both of methods above leave activity in destroyed state: assertFalse(mActivityTestRule.getActivity().isDestroyed()); fails.
I found another method (Destroy and restart Activity with Testing Support Library) that recreates activity instance, but does not keep its state through onSaveInstanceState