I have decided that one of the testing criteria for my application tests with Google\'s Espresso is:
Test should maintain Activity state after s
You can do it with uiautomator library
dependencies {
androidTestImplementation 'androidx.test.uiautomator:uiautomator:2.2.0'
}
ui automator require min sdk version 18 so if your app has a lower min sdk you need to create a new AndroidManifest.xml
in androidTest
folder
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:tools="http://schemas.android.com/tools"
package="your.package.name">
<uses-sdk tools:overrideLibrary="android.support.test.uiautomator.v18"/>
</manifest>
and then in your test
UiDevice device = UiDevice.getInstance(getInstrumentation());
device.setOrientationLeft();
device.setOrientationNatural();
device.setOrientationRight();
This more complete solution creates a custom Espresso ViewAction
and works well. It shows how to get the Activity
(even when it is an AppCompatActivity
) before calling its setRequestedOrientation()
method. It also has a clean caller interface:
onView(isRoot()).perform(orientationLandscape());
onView(isRoot()).perform(orientationPortrait());
I follow each orientation change with a 100 ms delay, though you may not need it.
After my own troubles with testing of the orientation I want to add that while lelloman's advice to use UiDevice
is correct from the documentation standpoint - unfortunately it doesn't work as expected in some cases.
I found that at least on the API 23 emulator rotation could stuck after the test's crash:
uiDevice.setOrientationLeft()
UiDevice
works but when test ends rotation is back the wrong one until you manually change rotation to "Auto-rotate";uiDevice.unfreezeRotation()
helps while test is running but after the test's end rotation is back to the wrong one.I don't have this issue on API 28.
So I found that using setRequestedOrientation
is the only solution for me.
You can't mix Robotium and Espresso tests. The best way sometimes to solve any issue is to check source code of desired but not comaptible method.
I'm pretty sure that you have already setUp()
method, which has code like:
myActivity = this.getActivity();
Use this to change your screen orientation change:
myActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
or
myActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
You may also need to use myActivity.getInstrumentation().waitForIdleSync();
or Thread.sleep(milliseconds);
in order to wait for the rotation end because it is performed in Async manner. The second methods depends on emulator/device so choose it wisely.
Hope it help.
How to rotate the screen:
public static void rotateScreen(Activity activity) {
final CountDownLatch countDownLatch = new CountDownLatch(1);
final int orientation = InstrumentationRegistry.getTargetContext()
.getResources()
.getConfiguration()
.orientation;
final int newOrientation = (orientation == Configuration.ORIENTATION_PORTRAIT) ?
ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE :
ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
activity.setRequestedOrientation(newOrientation);
getInstrumentation().waitForIdle(new Runnable() {
@Override
public void run() {
countDownLatch.countDown();
}
});
try {
countDownLatch.await();
} catch (InterruptedException e) {
throw new RuntimeException("Screen rotation failed", e);
}
}
The Activity
can be obtained from the ActivityRule.
If you have the only Activity in your test case, you can do:
Rule
.@Rule
public ActivityTestRule<TestActivity> mActivityTestRule = new ActivityTestRule<>(TestActivity.class);
Activity
and apply a screen rotation.mActivityTestRule.getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
mActivityTestRule.getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
That's a piece of pie!