© Denys Zelenchuk 2019
Denys ZelenchukAndroid Espresso Revealedhttps://doi.org/10.1007/978-1-4842-4315-2_10

10. Android Test Automation Tooling

Denys Zelenchuk1 
(1)
Zürich, Switzerland
 

This chapter contains information about the tools provided by the Android platform that are used in test automation. We will discuss topics about setting up virtual or physical devices for test automation, figure out how the Espresso Test Recorder can help us when writing automated tests, and learn how to run automated tests in the Firebase Test Lab.

Setting Up a Virtual or Physical Device for Test Automation

A properly configured virtual or physical device is a must-have for reliable tests. Here is a list of device properties that may affect test execution and produce flakiness in your tests:
  • System animations

  • Touch and hold delay

  • Virtual keyboard appearance

Let’s start with system animations. Unfortunately, Espresso cannot handle system animations, which may lead to flaky tests. This is one of Espresso’s major limitations. On the other hand, animations should be tested manually and disabling them in automated tests doesn’t harm us. The Android operation system has three system animation types:
  • Window animation scale —Sets the window animation playback speed so you can check its performance at different speeds. A lower scale results in a faster speed.

  • Transition animation scale —Sets the transition animation playback speed so you can check its performance at different speeds. A lower scale results in a faster speed.

  • Animation duration scale —Sets the animation’s duration.

These animation properties are available from the Settings ➤ System ➤ Developer option, inside the Drawing section, as shown in Figure 10-1.
../images/469090_1_En_10_Chapter/469090_1_En_10_Fig1_HTML.jpg
Figure 10-1

System animation properties in the device developer options

And of course, we want all animations to be disabled automatically. This is achievable in two ways. We can execute the following shell commands before the test runs or when the device starts.

Shell Commands to Set System Animation Properties.
adb shell settings put global animator_duration_scale 0.0
adb shell settings put global transition_animation_scale 0.0
adb shell settings put global window_animation_scale 0.0

The second option is to execute the same commands, but using a UiDevice instance before the test runs.

Setting System Animation Properties in the @BeforeClass Method .
companion object {
    @BeforeClass
    @JvmStatic
    fun setDevicePreferencies() {
        val uiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
        uiDevice.executeShellCommand("settings put global animator_duration_scale 0.0")
        uiDevice.executeShellCommand("settings put global transition_animation_scale 0.0")
        uiDevice.executeShellCommand("settings put global window_animation_scale 0.0")
    }
}

In this example, we used the @BeforeClass annotation to execute it once for the whole test class.

The second device property that can bring flakiness is the Touch and Hold Delay. You can find it in the System ➤ Accessibility section, as shown in Figure 10-2.
../images/469090_1_En_10_Chapter/469090_1_En_10_Fig2_HTML.jpg
Figure 10-2

The Touch and Hold Delay accessibility property

This property is responsible for setting the time used by the system to differentiate between click and long click actions. If a click’s touch time exceeds the Touch and Hold Delay limit, it’s interpreted as a long click. This is visible if you tap and hold the toolbar icon to see its content description. On some real devices, when this delay value is short, a single click may become a long click, which causes the automated UI test to fail. To avoid this, we can modify the Touch and Hold Delay value. The first option for doing so is to execute the following shell command (the delay value is in milliseconds):
adb shell settings put secure long_press_timeout 1500

The second option is run from inside the @BeforeClass method , as follows.

Setting Touch and Hold Delay in the @BeforeClass Method.
companion object {
    @BeforeClass
    @JvmStatic
    fun setDevicePreferencies() {
        val uiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
        uiDevice.executeShellCommand("settings put secure long_press_timeout 1500")
    }
}

By the way, the default Short value is set to 500 milliseconds, Medium is set to 1000 milliseconds, and Long is set to 1500 milliseconds.

Let’s now discuss the final device property that can cause flakiness in our tests—the virtual keyboard appearance. At first look, the virtual keyboard seems not related at all to test flakiness but there is one thing we have to keep in mind—Espresso for Android operates only in our application under the test context and it is not allowed to interact with any third-party applications.

Guess what? The virtual keyboard doesn’t belong to our application. So, there may be cases when mobile device performance becomes slow and the ViewActions.closeSoftKeyboard() method is not executed fast enough. At that point, if the tests need to click on UI elements that are hidden behind the virtual keyboard (which is supposed to be closed, but is still in the process of closing), they accidentally click on the keyboard instead. The following exception is thrown:
java.lang.SecurityException: Injecting to another application requires INJECT_EVENTS permission
To avoid this issue, we can manually disable the virtual keyboard appearance on the virtual device. Unfortunately, there is no nice way to do this on real devices unless you connect physical keyboards to them. To disable a virtual keyboard, navigate to Settings ➤ System ➤ Languages & Input ➤ Physical keyboard and disable the Show Virtual Keyboard option. Or, again, this can be done via the shell:
adb shell settings put secure show_ime_with_hard_keyboard 0

You can also execute the same command from inside the test, as follows.

Disabling a Virtual Keyboard in the @BeforeClass Method .
companion object {
    @BeforeClass
    @JvmStatic
    fun setDevicePreferencies() {
        val uiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
        uiDevice.executeShellCommand("settings put secure show_ime_with_hard_keyboard 0")
    }
}

After combining all the mentioned commands, here is what we get.

chapter10.devicesetup. DeviceSetupTest.kt .
companion object {
    @BeforeClass
    @JvmStatic
    fun setDevicePreferences() {
        val uiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
        uiDevice.executeShellCommand("settings put global animator_duration_scale 0.0")
        uiDevice.executeShellCommand("settings put global transition_animation_scale 0.0")
        uiDevice.executeShellCommand("settings put global window_animation_scale 0.0")
        uiDevice.executeShellCommand("settings put secure long_press_timeout 1500")
        uiDevice.executeShellCommand("settings put secure show_ime_with_hard_keyboard 0")
    }
}

It does not matter which approach you use to set test devices in a test friendly state; they will definitely make your automated tests more reliable and less flaky.

Exercise 23

Configuring a Device for Test Automation
  1. 1.

    Create an Android emulator and observe the default values for System Animations, Virtual Keyboard, and Touch and Hold Delay in the accessibility menu. Run the test implemented in chapter10.DeviceSetupTest.kt. After the test runs, observe the same properties’ values and compare the results.

     
  2. 2.

    Set the default emulator or device system animations, Virtual Keyboard, and Touch and Hold Delay states. Execute all shell commands manually from the terminal. Observe the mentioned properties afterward.

     
  3. 3.

    Create a shell script with all the shell commands from this paragraph that executes them on the connected device.

     

Using the Espresso Test Recorder Tool

The Espresso authors were probably inspired by the Selenium IDE test recorder and decided to add this same capability into Espresso as well. The Espresso Test Recorder tool allows inexperienced users to create Espresso UI tests with less effort. It became available and stable in Android Studio version 2.3.

The Test Recorder tool is integrated into Android Studio IDE and available from the Run ➤ Record Espresso Test menu, as shown in Figure 10-3.
../images/469090_1_En_10_Chapter/469090_1_En_10_Fig3_HTML.jpg
Figure 10-3

Record Espresso Test option in the Android Studio Run menu

Before starting, you should have a test device connected or a virtual device created in advance. After recording is triggered, you are asked to select a target device. After the application is built, it will be deployed to the target device and will run in debug mode. See Figure 10-4.
../images/469090_1_En_10_Chapter/469090_1_En_10_Fig4_HTML.jpg
Figure 10-4

Target device selection dialog

While recording is ongoing, application interactions will be tracked and shown inside recorder view. Figure 10-5 demonstrates adding a new TO-DO flow in the sample application.
../images/469090_1_En_10_Chapter/469090_1_En_10_Fig5_HTML.jpg
Figure 10-5

Espresso Test Recorder window

The Add Assertion button allows you to add an assertion of the following types (see Figure 10-6):
  • Text is—Equivalent to check(matches(withText()))

  • Exists—Equivalent to check(matches(isDisplayed()))

  • Does not exist—Equivalent to check(doesNotExist())

../images/469090_1_En_10_Chapter/469090_1_En_10_Fig6_HTML.jpg
Figure 10-6

Adding assertions to the Espresso Test Recorder

After you are done with the recording and you click the OK button, you will be asked to provide the name of the test class and select the test class language (Java or Kotlin). See Figure 10-7.
../images/469090_1_En_10_Chapter/469090_1_En_10_Fig7_HTML.jpg
Figure 10-7

Saving the recorded test in a test class file

You can’t save a recorded test in a test class that already exists. If you try to do this, the error in Figure 10-8 will be shown.
../images/469090_1_En_10_Chapter/469090_1_En_10_Fig8_HTML.jpg
Figure 10-8

Error when trying to save a recorded test into an existing file

By default, recorded tests are stored inside the tasks package , which is automatically created inside the application’s package. See Figure 10-9.
../images/469090_1_En_10_Chapter/469090_1_En_10_Fig9_HTML.jpg
Figure 10-9

Path where recorded tests are saved

The Espresso Test Recorder can be tweaked from inside Android Studio preferences. You can observe that with the default depth values (Max UI depth = 3, ScrollView detection = 5, and Assertion depth = 3), the test recorder and the application are quite slow. If you lowering them to 1 or 2, they become much more responsive. See Figure 10-10.
../images/469090_1_En_10_Chapter/469090_1_En_10_Fig10_HTML.jpg
Figure 10-10

Espresso Test Recorder preferences

Next, you can see how clicking on the Add TO-DO floating action button is recorded with the default depth values.

Click Add TO-DO Button Code Generated by Recorder with Default Depth Values.
val floatingActionButton = onView(
        allOf(withId(R.id.fab_add_task), withContentDescription("Add todo"),
                childAtPosition(
                        allOf(withId(R.id.coordinatorLayout),
                                childAtPosition(
                                        withClassName(`is`("android.widget.LinearLayout")),
                                        1)),
                        1),
                isDisplayed()))
floatingActionButton.perform(click())

Here is an example of the same action, but with the Max UI depth set to 1.

Click Add TO-DO Button Code Generated by Recorder with Depth Values set to 1.
val floatingActionButton = onView(
        allOf(withId(R.id.fab_add_task), isDisplayed()))
floatingActionButton.perform(click())

You can observe and compare how the add new TO-DO test code looks when recording it with the default depth values in the chapter10.testrecorder.AddTodoEspressoTestRecorder.kt class and with the depth values set to 1 in the chapter10.testrecorder.AddTodoEspressoTestRecorderLowerDepth.kt class.

After getting familiar with the Espresso Test Recorder, you’ll notice that:
  • For all the EditText fields, it adds the closeSoftKeyboard() ViewAction.

  • When the target view is part of the ScrollView layout, the scrollTo() ViewAction is added before another action has been done on it.

  • If the application requires a permission, GrantPermissionRule is added to the test class.

In general, the Espresso Test Recorder may be a good way to start with Espresso itself, but it has some drawbacks as well:
  • Application speed while recording is slow (even slower with higher depth values, but lowering the depth value can lead to failed tests).

  • Generated code can be massive and hard to read.

  • It has limited assertion support.

  • Automatically generated tests usually require additional customization.

  • There is no support for application delays caused by network requests, so you should manually create and register an IdlingResource.

  • WebView layouts are not supported.

Exercise 24

Using the Espresso Test Recorder
  1. 1.

    Record a test that adds and edits a new TO-DO with assertions. Save the test class in the Kotlin language. Observe the generated code. Run the recorded test.

     
  2. 2.

    Open Android Studio Preferences ➤ Espresso Test Recorder and lower the Max UI depth and Assertion Depth to 1. Record the test described in Step 1. Observe the generated code and compare it to the code from Step 1. Run the recorded test.

     
  3. 3.

    Record a test that triggers the Camera permission dialog. Observe the generated code. Run the recorded test.

     

Running Espresso Tests in the Firebase Test Lab from Android Studio

It is widely known that the Android platform, by its nature, has significant device fragmentation. To deal with this, you may have a wide range of mobile devices based on the usage statistics. But this is quite costly, taking into account the fact that you have to maintain it. Even if this is a must-have in manual testing, in test automation we tend to use Android emulators, custom device labs, or third-party services. Third-party services did provide such a possibility for mobile developers but they were not standardized and were costly. Then Google decided to bring its own device-testing solution into the Android ecosystem. It’s called the Firebase Test Lab. It allows developers to run automated tests on real devices or emulators without the need to maintain them.

Let’s look at how to start using Firebase and what benefits it brings. First, starting from https://firebase.google.com/ , you should navigate to the Firebase console and log in with your Google account (see Figure 10-11).
../images/469090_1_En_10_Chapter/469090_1_En_10_Fig11_HTML.jpg
Figure 10-11

The Firebase toolbar

There you will notice that you will already have a couple of sample projects to play with and the possibility to add your own by clicking on Add Project. See Figure 10-12.
../images/469090_1_En_10_Chapter/469090_1_En_10_Fig12_HTML.jpg
Figure 10-12

The Firebase welcome desktop

After clicking Add Project, you will be asked to provide the project name and select other parameters related to the service location. When the project name is provided, the project will automatically receive its project ID, which is a unique identifier for your Firebase project. See Figure 10-13.
../images/469090_1_En_10_Chapter/469090_1_En_10_Fig13_HTML.jpg
Figure 10-13

Firebase, Add a Project

After you are done with it, you will land on the Project Overview screen. From there, you can navigate to the Test Lab, as shown in Figure 10-14.
../images/469090_1_En_10_Chapter/469090_1_En_10_Fig14_HTML.jpg
Figure 10-14

The Firebase Test Lab initial state

It is now all set and ready to be used by our automated tests. Since we want to run them via Android Studio, we have to set up the proper test configuration from there. To do this, we open the Run ➤ Edit Configurations… menu, select Android Instrumentation Tests, and add a new one by clicking on the + button, as shown in Figure 10-15.
../images/469090_1_En_10_Chapter/469090_1_En_10_Fig15_HTML.jpg
Figure 10-15

Adding the Firebase Test Lab instrumentation test configuration

In the Deployment Target options, we should set the Firebase Test Lab Device Matrix option as a target and then sign in with the same Google account into the Firebase, as shown in Figure 10-16.
../images/469090_1_En_10_Chapter/469090_1_En_10_Fig16_HTML.jpg
Figure 10-16

Logging in to the Firebase Test Lab

After that you can select your project and configure the device matrix, as shown in Figure 10-17.
../images/469090_1_En_10_Chapter/469090_1_En_10_Fig17_HTML.jpg
Figure 10-17

Selecting the Firebase Test Lab project

Figure 10-18 shows how the device matrix dialog looks.
../images/469090_1_En_10_Chapter/469090_1_En_10_Fig18_HTML.jpg
Figure 10-18

Selecting the Firebase Test Lab device matrix

It’s worth mentioning that, for our sample project, we used the Spark pricing plan, which is free and has its limitations. You get 10 tests per day on virtual devices and five tests per day on real devices.

When all is ready, we can select and run the test using the Firebase test configuration, as shown in Figure 10-19.
../images/469090_1_En_10_Chapter/469090_1_En_10_Fig19_HTML.jpg
Figure 10-19

Running tests in the Firebase Test Lab inside Android Studio

When the test execution is finished, we can return to the Firebase Test Lab console and observe the test results from the last run, as shown in Figure 10-20.
../images/469090_1_En_10_Chapter/469090_1_En_10_Fig20_HTML.jpg
Figure 10-20

Test results overview in the Firebase Test Lab console

After clicking on the specific test execution, you will land at the detail test run description with the possibility to preview device logs, recorded video, and device performance during the test run (see Figure 10-21).
../images/469090_1_En_10_Chapter/469090_1_En_10_Fig21_HTML.jpg
Figure 10-21

Detailed test case overview in the Firebase Test Lab console

Exercise 25

Running Espresso and UI Automator Tests in the Firebase Test Lab
  1. 1.

    Configure your Firebase account, open the Firebase console, and set up the project.

     
  2. 2.

    In the Android Studio IDE, add a new Android Instrumentation Test configuration and connect to the project created in Step 1.

     
  3. 3.

    Run the tests and observe the results locally and inside the Firebase Test Lab console.

     
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.149.214.60