Introduction
Android's Testing Support library includes the UI Automator framework, which can be used to perform automated black-box testing on Android apps. Introduced in API Level 18, the framework allows developers to simulate user actions on the widgets that constitute an app's user interface.
In this tutorial, I am going to show you how to use the framework to create and run a basic user interface test for the default Calculator app.
Prerequisites
To follow along, you need:
- the latest build of Android Studio
- a device or emulator that runs Android 4.3 or higher
- a basic understanding of JUnit
1. Installing Dependencies
To use the UI Automator framework in your project, edit the build.gradle file in your project's app directory, adding the following dependencies:
androidTestCompile 'com.android.support.test:runner:0.2' androidTestCompile 'com.android.support.test:rules:0.2' androidTestCompile 'com.android.support.test.uiautomator:uiautomator-v18:2.1.0'
The Sync Now button should be on the screen now. When you click it, you should see an error that looks like this:
Click the Install Repository and sync project link to install the Android Support Repository.
If you are using the appcompat-v7 library and its version is 22.1.1, you need to add the following dependency to ensure that both the app and the test app are using the same version of com.android.support:support-annotations
:
androidTestCompile 'com.android.support:support-annotations:22.1.1'
Next, due to a bug in Android Studio, you need to exclude a file named LICENSE.txt using packagingOptions
. Failing to do so will lead to the following error when you try to run a test:
Execution failed for task ':app:packageDebugAndroidTest'. Duplicate files copied in APK LICENSE.txt File 1: ~/.gradle/caches/modules-2/files-2.1/org.hamcrest/hamcrest-core/1.1/860340562250678d1a344907ac75754e259cdb14/hamcrest-core-1.1.jar File 2: ~/.gradle/caches/modules-2/files-2.1/junit/junit-dep/4.10/64417b3bafdecd366afa514bd5beeae6c1f85ece/junit-dep-4.10.jar
Add the following snippet at the bottom of your build.gradle file:
android { packagingOptions { exclude 'LICENSE.txt' } }
2. Create a Test Class
Create a new test class, CalculatorTester
, by creating a file named CalculatorTester.java inside the androidTest directory. To create a UI Automator test case, your class must extend InstrumentationTestCase
.
Press Alt+Insert and then click SetUp Method to override the setUp
method.
Press Alt+Insert again and click Test Method to generate a new test method. Name this method testAdd
. The CalculatorTester
class should now look like this:
public class CalculatorTester extends InstrumentationTestCase{ @Override public void setUp() throws Exception { } public void testAdd() throws Exception { } }
3. Inspect the Launcher's User Interface
Connect your Android device to your computer and press the home button on your device to navigate to the home screen.
Go back to your computer and use your a file explorer or terminal to browse to the directory where you installed the Android SDK. Next, enter the tools directory inside it and launch uiautomatorviewer. This will launch UI Automater Viewer. You should be presented with a screen that looks like this:
Click the button that looks like a phone to capture a screenshot of your Android device. Note that the screenshot you just captured is interactive. Click the Apps icon at the bottom. In the Node Detail section on the right, you're now able to see various details of your selection as shown below.
To interact with items on the screen, the UI Automator testing framework needs to be able to uniquely identify them. In this tutorial, you will be using either the text
, the content-desc
, or the class
of the item to uniquely identify it.
As you can see, the Apps icon doesn't have any text
, but it does have a content-desc
. Make a note of its value, because you will be using it in the next step.
Pick your Android device up and touch the Apps icon to navigate to the screen that shows the apps installed on the device. Head back to UI Automater Viewer and capture another screenshot. Since you will be writing a test for the Calculator app, click its icon to look at its details.
This time the content-desc
is empty, but the text
contains the value Calculator. Make a note of this as well.
If your Android device is running a different launcher or a different version of Android, the screens and the node details will be different. This also means that you will have to make some changes in your code to match the operating system.
4. Prepare the Test Environment
Return to Android Studio to add code to the setUp
method. As its name suggests, the setUp
method should be used to prepare your test environment. In other words, this is where you specify what needs to be done before running the actual test.
You will now be writing code to simulate what you did on your Android device in the previous step:
- Press the home button to go to the home screen.
- Press the Apps icon to view all apps.
- Launch the Calculator app by tapping its icon.
In your class, declare a field of type UiDevice
and name it device
. This field represents your Android device and you will be using it to simulate user interaction.
private UiDevice device;
In the setUp
method, initialize device
by invoking the UiDevice.getInstance
method, passing in a Instrumentation
instance as shown below.
device = UiDevice.getInstance(getInstrumentation());
To simulate pressing the home button of the device, invoke the pressHome
method.
device.pressHome();
Next, you need to simulate a click event on the Apps icon. You can't do this immediately though, because the Android device will need a moment to navigate to the home screen. Trying to click the Apps icon before it is visible on the screen will cause a runtime exception.
To wait for something to happen, you need to call the wait
method on the UiDevice
instance. To wait for the Apps icon to show up on the screen, use the Until.hasObject
method.
To identify the Apps icon, use the By.desc
method and pass the value Apps to it. You also need to specify the maximum duration of the wait in milliseconds. Set it to 3000. This results in the following code block:
// Wait for the Apps icon to show up on the screen device.wait(Until.hasObject(By.desc("Apps")), 3000);
To get a reference to the Apps icon, use the findObject
method. Once you have a reference to the Apps icon, invoke the click
method to simulate a click.
UiObject2 appsButton = device.findObject(By.desc("Apps")); appsButton.click();
Like before, we need to wait a moment for the Calculator icon to show up on the screen. In the previous step, you saw that the Calculator icon can be uniquely identified by its text
field. We invoke the By.text
method to find the icon, passing in Calculator
.
// Wait for the Calculator icon to show up on the screen device.wait(Until.hasObject(By.text("Calculator")), 3000);
Use the findObject
and click
methods to obtain a reference to the Calculator icon and simulator a click.
UiObject2 calculatorApp = device.findObject(By.text("Calculator")); calculatorApp.click();
5. Inspect the Calculator's User Interface
Launch the Calculator app on your Android device and use UI Automater Viewer to inspect it. After capturing a screenshot, click the buttons to see how you can uniquely identify them.
For this test case, you will be making the calculator calculate the value of 9+9= and check if it shows 18 as the result. This means that you need to know how to identify the buttons with the labels 9, +, and =.
On my device, here's what I gathered from the inspection:
- The buttons containing the digits have matching
text
values. - The buttons containing the + and = symbols have the
content-desc
values set to plus and equals respectively. - The result is shown in an
EditText
widget.
Note that these values might be different on your device if you are using a different version of the Calculator app.
6. Create the Test
In the previous steps, you already learned that you can use the findObject
method along with either By.text
or By.desc
to get a reference to any object on the screen. You also know that you have to use the click
method to simulate a click on the object. The following code uses these methods to perform the calculation 9+9=. Add it to the testAdd
method of the CalculatorTester
class.
// Wait till the Calculator's buttons are on the screen device.wait(Until.hasObject(By.text("9")), 3000); // Select the button for 9 UiObject2 buttonNine = device.findObject(By.text("9")); buttonNine.click(); // Select the button for + UiObject2 buttonPlus = device.findObject(By.desc("plus")); buttonPlus.click(); // Press 9 again as we are calculating 9+9 buttonNine.click(); // Select the button for = UiObject2 buttonEquals = device.findObject(By.desc("equals")); buttonEquals.click();
At this point, you have to wait for the result. However, you can't use Until.hasObject
here because the EditText
containing the result is already on the screen. Instead, you have to use the waitForIdle
method to wait for the calculation to complete. Again, the maximum duration of the wait can be 3000 ms.
device.waitForIdle(3000);
Get a reference to the EditText
object using the findObject
and By.clazz
methods. Once you have the reference, call the getText
method to determine the result of the calculation.
UiObject2 resultText = device.findObject(By.clazz("android.widget.EditText")); String result = resultText.getText();
Finally, use assertTrue
to verify that the result is equal to 18.
assertTrue(result.equals("18"));
Your test is now complete.
6. Run the Test
To run the test, in the toolbar of Android Studio, select the class CalculatorTester
from the drop-down and click the play button on its right.
Once the build finishes, the test should run and complete successfully. While the test runs, you should be able to see the UI automation running on your Android device.
Conclusion
In this tutorial, you have learned how to use the UI Automator testing framework and the UI Automater Viewer to create user interface tests. You also saw how easy it is to run the test using Android Studio. Even though we tested a rather simple app, you can apply the concepts you learned here to test almost any Android app.
You can learn more about the testing support library on the Android Developers website.