What’s New in UIAutomator 2.0 and How to Get Started

screen-shot-2016-10-02-at-8-44-56-pm

Dear Testdroiders,

Time to time we cover new frameworks here at Testdroid Blog and despite UIAutomator really isn’t a new framework for Android app testing, some things have changed quite a lot from the version 1.x to 2.0. That being said, the fundamental purpose of UIAutomator framework hasn’t changed and it still allows its users to focus on UI testing and provides a lightweight, but very efficient and easy-to-learn API to get things done fast.

Let’s see how things are different between these two versions – and how you should prepare tests.

howto-uiautomator-1

The UIAutomator 2.0 is a test automation framework by Google that allows developers to build streamlined and application-specific functional UI tests for Android apps. The new UIAutomator 2.0 is still a Java based library containing a compact API to create tests and use its execution engine to automate and run those tests on real Android devices. It’s actually a pretty good framework to write black-box tests and the test code doesn’t need rely on application implementation anyhow.

The UIAutomator has been widely adopted and used for Android app testing, however, it’s definitely not the most popular framework at the moment. It certainly has its perks, especially now when it’s based on Android instrumentation and developers can use Gradle to build and run those tests. It certainly makes UIAutomator more appealing when things are finally working smooth with Android Studio environment.

Introduction to UIAutomator 2.0 API

Each and every framework has its own pros and cons when it comes to use cases, scalability and robustness, and one of those advantages UIAutomator 2.0 has is definitely its API. It basically provides some useful classes for developers to use. Those classes, with additional features, interfaces and exceptions, allow developers to capture and manipulate user interface components on the target app. The classes are:

  • By – a utility class which enables the creation of BySelector.
  • BySelector – Specifies a criteria for matching UI elements during a call to findObject(…)
  • UiCollection – This class is used to enumerate UI elements for the purpose of counting, or targeting a sub elements by a child’s text or description.
  • UiObject – A UiObject contains information to help it locate a matching view at runtime based on the UiSelector properties specified in its constructor. Once UiObject instance is created it can be reused for different views that match the selector criteria.
  • UiObject2 – Represents a UI element. This is slightly different from UiObject as UiObject2 elements can be used even an underlying view object is terminated.
  • UiScrollable – UiScrollable is a UiCollection and provides support for searching for items in scrollable layout elements.
  • UiSelector – This specifies the UI elements in the layout hierarchy for tests to target, filtered by properties such as text value, content-description, class name, and state information, among others.
  • Configurator – Allows to set parameters for running UIAutomator tests and those settings will impact immediately.

More about UIAutomator classes can be found in the documentation.

Also, importing these classes to your project has changed from UIAutomator 1.x and com.android.uiautomator.core.* isn’t used anymore:

// Imports with UIAutomator 1.x
import com.android.uiautomator.core.UiCollection;
import com.android.uiautomator.core.UiDevice;
import com.android.uiautomator.core.UiObject;
import com.android.uiautomator.core.UiScrollable;
import com.android.uiautomator.core.UiSelector;

// Imports with UIAutomator 2.0
import android.support.test.uiautomator.By;
import android.support.test.uiautomator.BySelector;
import android.support.test.uiautomator.UiDevice;
import android.support.test.uiautomator.UiObject2;
...

I’ll showcase a working skeleton example on the bottom of this article.

Differences between UIAutomator 1.0 and 2.0

The Build System

While you used Maven and/or Ant with the old version of UIAutomator the new one utilizes capabilities of Gradle as a build system. Building and running tests are easy with gradlew connectedCheck command and you don’t need to hassle with maven anymore.

In addition, Gradle provides a way to build plugins that enable seamless execution of tests on real physical devices on cloud service. As Testdroid Cloud provides the largest and the most diverse option of real Android devices for app developers, all these devices are usable and accessible via Gradle plugin and test runs can be started in seconds.

Test Assets – from zip/jar to APK

The major change in the new UIAutomator 2.0 is that test packages produced are now APKs. This has been the standard way to implement instrumentation tests and UIAutomator 1.x had tests either as .jar or .zip files. Making UIAutomator 2.0 fully Android instrumentation capable is definitely good way to go forward and most likely it will make this framework usable by larger audience.

Android Debugging Bridge

If you are running UIAutomator tests in your local environment, there is also a minor difference how ADB deals with UIAutomator 1.x vs 2.0. As you have probably launched your tests using the following command line with UIAutomator 1.x:

adb shell uiautomator runtest UiTest.jar -c package.name.ClassName

With UIAutomator 2.0 you’ll need to change that ADB liner a bit e.g. to include test runner that will be used for test session:

adb shell am instrument -e class com.example.app.MyTest com.example.app.test/android.support.test.runner.AndroidJUnitRunner

Project Types in Cloud

As mentioned, one remarkable difference between UIAutomator 1.x and 2.0 is the test output file. With Testdroid Cloud, you can basically upload UIAutomator 2.0 tests as an APK and use regular Android project as your test run. If you are still using any of those older versions of UIAutomator, you still need to create Android UIAutomator project for your test runs.

Another notable difference for test runs is the custom test runner that has to be set for test runs. As UIAutomator 2.0 uses android.support.test.runner.AndroidJUnitRunner instead of android.test.InstrumentationTestRunner. This can be configured in step #4 of test run creation wizard:

Screen Shot 2016-06-01 at 1.24.50 PM

How to Get Started with UIAutomator 2.0

First of all, you have check the Android Studio environment is properly configured and you have all required components installed. Start with SDK Manager and check that Android Support Repository is installed on your machine. This can be found under SDK Tools panel:

SDK Manager and SDK Tools

After installation, Android Support Repository and its files are located at <sdk>/extras/android/m2repository directory.

Gradle Build Configuration

Next thing to check is that all dependencies are properly configured in gradle.build configuration file:

apply plugin: 'com.android.application'

android {
   compileSdkVersion 23
   buildToolsVersion '23.0.1'
   defaultConfig {
       minSdkVersion 18
       targetSdkVersion 23
       versionCode 1
       versionName "1.0"
       testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
   }
   buildTypes {
       release {
           minifyEnabled false
           proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
       }
   }
   productFlavors {
   }
}

dependencies {
   compile 'com.android.support.test:testing-support-lib:0.1'
   compile 'com.android.support.test.uiautomator:uiautomator-v18:2.0.0'
}

Rest of these parameters set in gradle.build are varying based on your application and what is it build for, but the bolded lines in above example are must to be included.

Android Manifest File

Changes in Android Manifest file are also quite minimalistic – and actually the whole Manifest file is as brief as follows:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:tools="http://schemas.android.com/tools"
 xmlns:android="http://schemas.android.com/apk/res/android"
 package="com.bitbar.uiautomator.sample">

 <uses-sdk tools:overrideLibrary="android.support.test.uiautomator.v18"/>

 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
</manifest>

A Skeleton/Example for UIAutomator 2.0 Test Script

First and forement, it’s very important to add @RunWith(AndroidJUnit.class) and @SdkSuppress(minSdkVersion = 18) as part of the your test script. Also, adding @Test for every test method is required!

Okay, let’s take a look at an example. Imports for an example test script goes as follows:

package com.bitbar.uiautomator.sample;

import android.content.Context;
import android.content.Intent;
import android.os.Environment;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SdkSuppress;
import android.support.test.runner.AndroidJUnit4;
import android.support.test.uiautomator.By;
import android.support.test.uiautomator.BySelector;
import android.support.test.uiautomator.UiDevice;
import android.support.test.uiautomator.UiObject2;
import android.util.Log;

import org.junit.Before;
import org.junit.runner.RunWith;

import java.io.File;

import static org.hamcrest.CoreMatchers.notNullValue;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;

As said before, there is a minor difference with imports compared to older version of UIAutomator, but good news definitely is that there are new classes available for the new version. Use of those will make UIAutomator a bit more slick and easier to use in different test cases.

Remember to add RunWith and SdkSuppress annotations, as well as @Test annotation when applicable:

@RunWith(AndroidJUnit4.class)
@SdkSuppress(minSdkVersion = 18)
public class Test {

    private UiDevice mDevice;

    @Before
    public void before() {
        // Initialize UiDevice instance
        mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());

        assertThat(mDevice, notNullValue());

        // Start from the home screen
        mDevice.pressHome();

    }

    @org.junit.Test
    public void test() throws InterruptedException {
        openApp("com.example.app");

        UiObject2 editText = waitForObject(By.res("com.example.app:id/numboard_pwd_edittext"));

        takeScreenshot("screenshot-1.png");

        editText.setText("123456");
        UiObject2 protectObject = waitForObject(By.text("Submit"));
        protectObject.click();

        takeScreenshot("screenshot-2.png");

        Thread.sleep(10000);
    }

    private void openApp(String packageName) {
        Context context = InstrumentationRegistry.getInstrumentation().getContext();
        Intent intent = context.getPackageManager().getLaunchIntentForPackage(packageName);
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
        context.startActivity(intent);
    }

    private UiObject2 waitForObject(BySelector selector) throws InterruptedException {
        UiObject2 object = null;
        int timeout = 30000;
        int delay = 1000;
        long time = System.currentTimeMillis();
        while (object == null) {
            object = mDevice.findObject(selector);
            Thread.sleep(delay);
            if (System.currentTimeMillis() - timeout > time) {
                fail();
            }
        }
        return object;
    }

    private void takeScreenshot(String name) {
        Log.d("TEST", "takeScreenshot");
        String dir = String.format("%s/%s", Environment.getExternalStorageDirectory().getPath(), "test-screenshots");
        File theDir = new File(dir);
        if (!theDir.exists()) {
            theDir.mkdir();
        }
        mDevice.takeScreenshot(new File(String.format("%s/%s", dir, name)));
    }
}

Allright, that’s all folks! Enjoy your testing with UIAutomator 2.0!


The Beginner’s Guide of Using Appium for Mobile App Testing

Learn all the basics about Appium, how to set it up and how to use it for mobile app testing.

Download

  • Roman

    Nice and helpfull article. Thanks a lot!

  • Allie

    I keep getting this error when I run this code:

    E/UiAutomatorBridge: failed to save screen shot to file
    java.io.FileNotFoundException: /storage/emulated/0/test-screenshots/test1.png: open failed: ENOENT (No such file or directory)

    Can you help me, please?

    • Michał

      Are you sure you have in the manifest file?

      • Allie

        Yes, I did. It turned out the problem was I was using an emulator with API 23. I switched to using one with API 22, and it worked like a charm- thank you!!!

  • Karthika Reddy S

    How do we get command line parameters with new UIAutomator?
    Earlier we were passing params like this:
    adb shell uiautomator runtest UiTest.jar -c package.name.ClassName -e paramKey paramValue
    And in Code we were getting Params by getParams() API . However it is deprecated now

By continuing to use the site, you agree to the use of cookies. more information

The cookie settings on this website are set to "allow cookies" to give you the best browsing experience possible. If you continue to use this website without changing your cookie settings or you click "Accept" below then you are consenting to this.

Close