Add Espresso and UiAutomator tests to your Surface Duo app
Espresso and UiAutomator are both testing frameworks provided by AndroidX libraries. Espresso is used to find and interact with UI elements within an app, while UiAutomator provides cross-app testing functionality and access to device sensors.
To learn more about these testing frameworks, check out these resources:
In your Android Studio Project, you'll be writing these UI tests in the androidTest section, where the default test file is named ExampleInstrumentedTest. And remember, disable animations on your device before running your UI tests.
Dependencies
Add the following dependencies to your app's build.gradle file:
android {
defaultConfig {
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
}
dependencies {
testImplementation "junit:junit:4.13"
androidTestImplementation "androidx.test.ext:junit:1.1.1"
androidTestImplementation "androidx.test.espresso:espresso-core:3.2.0"
androidTestImplementation "androidx.test:runner:1.2.0"
androidTestImplementation "androidx.test:rules:1.2.0"
androidTestImplementation "androidx.test.uiautomator:uiautomator:2.2.0"
}
If testing with a WebView, androidTestImplementation "androidx.test.espresso:espresso-web:3.2.0"
should also be added to the dependencies section.
Note
If using a separate dependencies.gradle file, see the app samples repo for examples of how the add the necessary dependencies.
Create rules for tests
JUnit rules can be added to your tests to specify additional information about subsequent tests. One of the most common rules used is to define a main activity for the tests to be applied to, as shown below:
@RunWith(AndroidJUnit4::class)
class PhotoEditorUITest {
@get:Rule
val activityRule = ActivityTestRule(MainActivity::class.java)
}
Write dual-screen tests
Basics
Use the UiDevice class provided by UiAutomator to find your device and change its spanning/rotation configurations, and then use Espresso to check that UI elements behave as expected.
As shown in the example below, the swipe method can be used to simulate spanning and unspanning. To make your tests are as reliable as possible, try to group tests together that need the same configuration so you don’t have to make multiple spanning and unspanning requests.
@Test
fun testSpan() {
val device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
// Span the app (from the left side)
device.swipe(675, 1780, 1350, 900, 400)
// Test that UI element appears
onView(withId(R.id.yourElement)).check(matches(isDisplayed()))
// Unspan the app (to the left side)
// device.swipe(2109, 1780, 675, 900, 200)
// Test that UI element has disappeared
// onView(withId(R.id.yourElement)).check(matches(not(isDisplayed())))
}
Other useful UiAutomator functions include setOrientationNatural, unfreezeRotation, and pressHome. If you want to test cross-app functionality, you can also use UiAutomator to launch other apps.
Helper functions
These basic helper functions can be used for simulating spanning behavior:
companion object {
// testing device
val device: UiDevice = UiDevice.getInstance(getInstrumentation())
// Swipe constants
const val leftX: Int = 675 // middle of left screen
const val rightX: Int = 2109 // middle of right screen
const val middleX: Int = 1350 // hinge area
const val bottomY: Int = 1780 // bottom of screen
const val middleY: Int = 900 // middle of screen
const val spanSteps: Int = 400 // spanning swipe
const val unspanSteps: Int = 200 // unspanning swipe
const val switchSteps: Int = 100 // swipe to switch from one screen to the other
const val closeSteps: Int = 50 // swipe to close app
}
private fun spanFromLeft() {
device.swipe(leftX, bottomY, middleX, middleY, spanSteps)
}
private fun unspanToLeft() {
device.swipe(rightX, bottomY, leftX, middleY, unspanSteps)
}
private fun spanFromRight() {
device.swipe(rightX, bottomY, middleX, middleY, spanSteps)
}
private fun unspanToRight() {
device.swipe(leftX, bottomY, rightX, middleY, unspanSteps)
}
private fun switchToLeft() {
device.swipe(rightX, bottomY, leftX, middleY, switchSteps)
}
private fun switchToRight() {
device.swipe(leftX, bottomY, rightX, middleY, switchSteps)
}
private fun closeLeft() {
device.swipe(leftX, bottomY, leftX, middleY, closeSteps)
}
private fun closeRight() {
device.swipe(rightX, bottomY, rightX, middleY, closeSteps)
}
To test if an app is spanned, define a rule that connects to the main activity and use it to replace activityRule
in this function:
private fun isSpanned(): Boolean {
onIdle() // wait until layout changes have been fully processed before checking
return ScreenHelper.isDualMode(activityRule.activity)
}
To make sure all of the helper functions work as expected, add import org.hamcrest.CoreMatchers.`is` as iz
to your import statements and then run the following test:
/**
* Runs helper functions and checks that they work as expected
*
* @precondition device in portrait mode, no other applications are open
* (so app by default opens on left screen)
*/
@Test
fun testSpanningHelperFunctions() {
spanFromLeft()
assertThat(isSpanned(), iz(true))
unspanToRight()
assertThat(isSpanned(), iz(false))
spanFromRight()
assertThat(isSpanned(), iz(true))
unspanToLeft()
assertThat(isSpanned(), iz(false))
switchToRight()
switchToLeft()
closeLeft()
}
Troubleshooting tips
If the testSpanningHelperFunctions
test fails or you encounter other testing issues:
- Adjust the step constants - certain gestures need to be slow enough to ensure they are processed correctly. 100 steps take approximately 0.5 seconds.
- Change the x and y constants, which represent pixel values on the screen. Each screen is 1350 x 1800 px, and the hinge gap is 84 px wide (Surface Duo dimensions).
- Add IdlingResources to tests that load data or perform other asynchronous operations that may affect UI tests.
Summary
UI testing for Surface Duo apps can be accomplished by using a combination of the Espresso and UiAutomator testing frameworks. In most cases, the swipe method from UiAutomator is all you need to simulate dual-screen events, and then Espresso can be used normally to interact with UI elements in your Surface Duo app.
For examples of UI testing in Surface Duo apps, check out these resources: