Do you save and restore state of your activities, fragments and custom views? Do you test them?
One way to test saving and restoring state is to rotate the screen in your Espresso test.
private void rotateScreen() { Context context = InstrumentationRegistry.getTargetContext(); int orientation = context.getResources().getConfiguration().orientation; Activity activity = activityRule.getActivity(); activity.setRequestedOrientation( (orientation == Configuration.ORIENTATION_PORTRAIT) ? ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE : ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); }
With this helper function, you can write tests like this:
@Test public void incrementTwiceAndRotateScreen() { onView(withId(R.id.count)) .check(matches(withText("0"))); onView(withId(R.id.increment_button)) .perform(click(), click()); onView(withId(R.id.count)) .check(matches(withText("2"))); rotateScreen(); onView(withId(R.id.count)) .check(matches(withText("2"))); }
Source code
https://github.com/chiuki/espresso-samples/
under rotate-screen
Like this article? Take a look at the outline of my Espresso book and fill in this form to push me to write it! Also check out the published courses: https://gumroad.com/chiuki
Inline coding questions will not be answsered. Instead, ask on StackOverflow and put the link in the comment.
Yeah we do this in our Robotium UI tests (Yes I really want to switch to Espresso! :-)
ReplyDeletedid you face any issues with StrictMode? I keep getting StrictMode$InstanceCountViolation after orientation change.
ReplyDeleteI tried adding StrictMode and it runs fine. How are you using StrictMode, and what device do you run it on? Do you get the same error when you rotate the device by hand?
DeleteI can easily reproduce the issue by adding StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().detectAll().penaltyLog().penaltyDeath().build()); to @Before in your test class. I need to double check it but it seems that ActivityThreadRule keeps a reference to the first activity. Tested with Genymotion Nexus 5 - API 21.
DeleteI've created a ticket to address this issue - https://code.google.com/p/android/issues/detail?id=189768
DeleteIf you have any references that have yet to be deallocated the new instance of your activity is alive while your dead activity is trying to die, the activity will not be completely destroyed until all associated refrences to the activity are gone, Hence the instance count violation. I have seen and dealt with this before.
ReplyDelete-- Also with Espresso, if you are testing anything with an adapter and change the orientation you should wait before testing anything related to adapter count. if you change orientation and then talk to the adapter before its notifydatasetchanged() on an attached fragment (because fragment get detached not destroyed) is called you can get an illegal state exception. (in my case i had different getCount() values based on my orientation.)
There's also ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED, which caused some issues for me n the past. If that's the case, I switch to LANDSCAPE, since the initial state is usually PORTRAIT. Also, I had to add
ReplyDeletegetInstrumentation().waitForIdleSync();
since in some cases the next op/check wasn't Espresso synchronized and didn't wait for the rotation to complete.
Thanks for your Espresso posts!
Hi, and thanks a lot for this code gem!
ReplyDeleteI wanted to perform(scrollTo()) on views after I called the rotateScreen() method. It's important to notice that methods like this will not work any more, because the screen orientation has not changed (only the activity orientation has).
So, beware of using methods like scrollTo() when your activity has a different orientation than the screen - they will not work.
This unfortunately will cause issues for certain activities that lock their orientations.
ReplyDeleteWhat if you manually call `activty.recreate()`?
I don't know. Can you try it and share the results? Thanks!
Deleteactivity.recreate() worked great for me!
Deletehttp://stackoverflow.com/a/35139887/891242