Mobile automation testing for Android with Appium

February 06, 2016

Table of content

Introduction

If you are a web developer who cares about quality, most probably you have heard about Selenium and the advantages of using such a tool for test automation (check this our for learning how to run your own continuous integration solution with Selenium).

Now, if you are a mobile developer, at this stage you might have suffered in your own skin how much harder it is to test your app due to the existence of different platforms, different OS versions and even multiple devices. Imagine how great it would be to write your tests only once and run them on different platforms. Then, maybe today is your lucky day, because we want to tell you about Appium, a tool inspired by the Selenium WebDriver that allows you to write tests against multiple platforms using the same API.

The philosophy behind Appium relies on the following principles [1]:

  • You shouldn’t have to recompile your app or modify it in any way in order to automate it.
  • You shouldn’t be locked into a specific language or framework to write and run your tests.
  • A mobile automation framework shouldn’t reinvent the wheel when it comes to automation APIs.
  • A mobile automation framework should be open source, in spirit and practice as well as in name!

We guarantee that Appium is a great tool, however its installation might be a little bit cumbersome. In this tutorial we show you all the steps required to successfully install Appium in an Ubuntu server. We had several issues during the installation and we couldn’t find a proper step-by-step tutorial for doing so, that’s why we want to contribute by avoiding you some headaches.

NOTE: using Appium for testing an iOS app requires a machine running OS X and Xcode (stack overflow thread). This Appium tutorial will focus uniquely on the Android platform.

Installing Appium

For this tutorial we will rely on an Ubuntu 14.04 server distribution. Note that our aim is to build a system that helps running our mobile tests in a headless fashion, i.e., without requiring a physical display. In this sense, we assume the following requirements as our starting point:

Requirements

  • Ubuntu 14.04
  • git
  • Python (this tutorial uses version 2.7.6)
  • pip

Before we are able to run Appium we need to make sure that the following tools are accessible in our system:

Summary of tools required by Appium

  • Java SDK 1.7: openjdk-7-jdk package must be installed. Do not confuse it with openjdk-7-jre, which contains just the Java Runtime Environment.
  • Apache Ant: Java version of GNU make for building Java applications
  • Apache Maven: Java dependency management and build system
  • rvm: Ruby Version Manager
  • gem: Ruby package manager
  • bundler: Ruby dependency manager
  • node: Javascript runtime
  • npm: Node Package Manager
  • grunt: Javascript task runner

These tools can be installed by following the next steps.

Step 0

Before you start downloading the tools, we suggest you create a folder in your home directory that will be used to keep the files and later create the required environment variables in your path. For example, we are using a folder called “workspace”.

1. Install Java

$ sudo apt-get install openjdk-7-jdk

Appium requires the JAVA_HOME variable and java in your path. In order to do so, edit the file .bashrc:

$ vim .bashrc
     export JAVA_HOME="/usr/lib/jvm/java-7-openjdk-amd64"
     export PATH="$PATH:$JAVA_HOME"
$ source .bashrc

Run the following command to check that java is accessible:

$ java -version

You should get the following output in your terminal:

java version "1.7.0_95"
OpenJDK Runtime Environment (IcedTea 2.6.4) (7u95-2.6.4-0ubuntu0.14.04.1)
OpenJDK 64-Bit Server VM (build 24.95-b01, mixed mode)

2. Install Ant

Move to the workspace folder we created in step 0 and download the latest Ant version.

At the time of writing the latest Ant version is 1.9.6:

$ wget http://www.eu.apache.org/dist//ant/binaries/apache-ant-1.9.6-bin.tar.gz

When it is done, just uncompress the file and delete the original .tar.gz since we won’t need it anymore.

$ tar -xvzf apache-ant-1.9.6-bin.tar.gz
$ rm apache-ant-1.9.6-bin.tar.gz

Now you will have a folder called apache-ant-1.9.6 within your workspace folder. You need to use that folder to create the ANT_HOME in your .bashrc file:

$vim .bashrc
     export ANT_HOME="$HOME/workspace/apache-ant-1.9.6"
     export PATH="$PATH:$ANT_HOME/bin" # Add ant to PATH
$source .bashrc

From the ANT_HOME directory run

$ ant -f fetch.xml -Ddest=system

in order to get the library dependencies of most of the Ant tasks that require them. If you don’t do this, many of the dependent Ant tasks will not be available.

3. Install maven

Within your workspace folder, download the latest version of Maven. At the time of writing this is version 3.3.9:

$ wget http://www.us.apache.org/dist/maven/maven-3/3.3.9/binaries/apache-maven-3.3.9-bin.tar.gz
$ tar -xvzf apache-maven-3.3.9-bin.tar.gz

Delete the .tar.gz file:

$ rm apache-maven-3.3.9-bin.tar.gz

Create the MAVEN_HOME variable and add it to the path:

$ vim .bashrc
     export MAVEN_HOME="$HOME/workspace/apache-maven-3.3.9"
     export PATH="$PATH:$MAVEN_HOME/bin"
$source .bashrc

Afterwords, run the following command from the terminal to check that Maven has been properly configured:

$mvn -v

If everything is fine, you should get the following output:

Apache Maven 3.3.9 (bb52d8502b132ec0a5a3f4c09453c07478323dc5; 2015-11-10T17:41:47+01:00)
Maven home: /home/6020peaks/workspace/apache-maven-3.3.9
Java version: 1.7.0_91, vendor: Oracle Corporation
Java home: /usr/lib/jvm/java-7-openjdk-amd64/jre
Default locale: en_US, platform encoding: ANSI_X3.4-1968
OS name: "linux", version: "3.13.0-74-generic", arch: "amd64", family: "unix"

4. Install rvm

From a terminal install the mapis public key:

$ gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3

Then proceed installing rvm with ruby:

$ \curl -sSL https://get.rvm.io | bash -s stable --ruby

Once this is done, proceed updating RubyGems and Bundler:

$ gem update --system
$ gem install --no-rdoc --no-ri bundler
$ gem update
$ gem cleanup

5. Install node

The first rule to install node in the right way is to avoid the use of apt-get, otherwise it will need sudo grants and Appium will not work correctly. Instead install linuxbrew and then install node from it. Shortly, linuxbrew is a package manager for linux forked from the original homebrew for OS X.

You can install linuxbrew in Ubuntu by running the following commands.

First install the linuxbrew dependencies:

$ sudo apt-get install build-essential curl git m4 python-setuptools ruby texinfo libbz2-dev libcurl4-openssl-dev libexpat-dev libncurses-dev zlib1g-dev

Then install linuxbrew by running:

$ ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Linuxbrew/linuxbrew/go/install)"

Once installed, add brew to your path:

$ vim .bashrc
$ export PATH="$PATH:$HOME/.linuxbrew/bin"
$ source .bashrc
$ brew doctor

Now you are in conditions to install node from brew:

$ brew install node

Note that this step can take a little bit of time, so please be patient and do not close the terminal. Once the process is done, check that node and npm are successfully installed by running:

$ node --version
$ npm --version

6. Install grunt

Simply run the following command in your terminal:

$ npm install -g grunt grunt-cli

7. Install Appium

Change the directory to the workspace folder you created at the beginning and then clone the Appium project using git:

$ git clone git://github.com/appium/appium.git

Now, at this stage is where the oficial Appium documentation gets confusing. If you are going through that guide, the next steps are to run the following commands in order to execute a collection of scripts that will set up Appium correctly before you are able to start it and test your app with it.

$ cd appium;
$ ./reset.sh —android  --verbose

However, that guide assumes that you already have Android perfectly configured in your environment and ready for Appium. If that is your case, then you should not have any issue, but otherwise you should proceed with our instructions in the next section.

Setting up a headless installation of Android

As we are aiming to build a headless configuration for our test automation system, all the instructions that follow just make use of a terminal. Even though it is a bit more tedious than using the GUI, the advantage is that you can use the commands to build your own script to automatise the installation process.

The first step is to install the latest Android SDK for linux. Change to your workspace folder and run the following commands:

$ wget http://dl.google.com/android/android-sdk_r24.4.1-linux.tgz
$ tar -xvzf android-sdk_r24.4.1-linux.tgz
$ rm android-sdk_r24.4.1-linux.tgz

Then create the ANDROID_HOME variable in .bashrc and add tools and platforms_tools to the path:

export ANDROID_HOME="$HOME/workspace/android-sdk-linux"
export PATH="$PATH:$ANDROID_HOME/tools"
export PATH="$PATH:$ANDROID_HOME/platform-tools"

Refresh your environment so that the new variables are considered by your terminal:

$ source .bashrc

Once we have the Android SDK ready, the next step is to install the Android APIs that our apps will target in the tests. Note that Appium requires API level 17+ in order to work properly.

Run the following command to see the list of available packages:

$ android list sdk --all

This will render a list like the following (edited for short):

Refresh Sources:
  Fetching https://dl.google.com/android/repository/addons_list-2.xml
  Validate XML
  Parse XML
  Fetched Add-ons List successfully
  Refresh Sources
  Fetching URL: https://dl.google.com/android/repository/repository-11.xml
  Validate XML: https://dl.google.com/android/repository/repository-11.xml
==== shorted ====
Packages available for installation or update: 160
   1- Android SDK Tools, revision 24.4.1
   2- Android SDK Tools, revision 25.0.5 rc6
   3- Android SDK Platform-tools, revision 23.1
   4- Android SDK Build-tools, revision 23.0.2
   5- Android SDK Build-tools, revision 23.0.1
   6- Android SDK Build-tools, revision 23 (Obsolete)
==== shorted ====
  26- SDK Platform Android 6.0, API 23, revision 2
  27- SDK Platform Android 5.1.1, API 22, revision 2
  28- SDK Platform Android 5.0.1, API 21, revision 2
  29- SDK Platform Android 4.4W.2, API 20, revision 2
  30- SDK Platform Android 4.4.2, API 19, revision 4
  31- SDK Platform Android 4.3.1, API 18, revision 3
  32- SDK Platform Android 4.2.2, API 17, revision 3
  33- SDK Platform Android 4.1.2, API 16, revision 5
  34- SDK Platform Android 4.0.3, API 15, revision 5
  35- SDK Platform Android 4.0, API 14, revision 4 (Obsolete)
  36- SDK Platform Android 3.2, API 13, revision 1 (Obsolete)
  37- SDK Platform Android 3.1, API 12, revision 3 (Obsolete)
  38- SDK Platform Android 3.0, API 11, revision 2 (Obsolete)
  39- SDK Platform Android 2.3.3, API 10, revision 2
  40- SDK Platform Android 2.3.1, API 9, revision 2 (Obsolete)
  41- SDK Platform Android 2.2, API 8, revision 3
  42- SDK Platform Android 2.1, API 7, revision 3 (Obsolete)
  43- SDK Platform Android 2.0.1, API 6, revision 1 (Obsolete)
  44- SDK Platform Android 2.0, API 5, revision 1 (Obsolete)
  45- SDK Platform Android 1.6, API 4, revision 3 (Obsolete)
  46- SDK Platform Android 1.5, API 3, revision 4 (Obsolete)
  47- SDK Platform Android 1.1, API 2, revision 1 (Obsolete)
==== shorted ====

The most important piece of information in this list is the first number at the beginning of each line, because this is the identification number of the package that we are willing to install. You can install one or more packages at the same time with the following command:

$ android update sdk -u -a -t 1,2,3,4,..,n

IMPORTANT NOTE: Make sure you install the API 19. We detected an open issue in the Appium source code that requires the API 19 in order to create a bootstrap project for Android. For more details check the following files on github:

grunt-helpers.js (line 399 to 412)

module.exports.setupAndroidBootstrap = function (grunt, cb) {
  var projPath = path.resolve(__dirname, "lib", "devices", "android",
      "bootstrap");
  var args = ["create", "uitest-project", "-n", "AppiumBootstrap", "-t",
              "android-19", "-p", "."];
  // TODO: possibly check output of `android list target` to make sure api level 19 is available?
  setupAndroidProj(grunt, projPath, args, cb);
};

module.exports.setupAndroidApp = function (grunt, appName, cb) {
  var appPath = path.resolve(__dirname, "sample-code", "apps", appName);
  var args = ["update", "project", "--subprojects", "-t", "android-19", "-p", ".", "-n", appName];
  setupAndroidProj(grunt, appPath, args, cb);
};

For the next step you need to install ABI for the android API that you installed. You can choose among several ABI options. This is necessary because if your target API does not have at least one ABI installed, then you won’t be able to create an emulator for it.

In our configuration we proceeded by installing the armeabi-v7a for API 19. You can do so by running the same command as before with the right package number that you see in your own listing, e.g.:

$ android update sdk -u -a -t 120

Note: replace the -t argument (120) with the right package number that you want to install.

Now we are ready to create a new android emulator. Check this out for more information about handling android virtual devices (AVD) from your command line.

Run the following command to see which android images are available in our system already.

$ android list targets

You should get an output like this:

Available Android targets:
----------
id: 1 or "android-19"
     Name: Android 4.4.2
     Type: Platform
     API level: 19
     Revision: 4
     Skins: HVGA, QVGA, WQVGA400, WQVGA432, WSVGA, WVGA800 (default), WVGA854, WXGA720, WXGA800, WXGA800-7in
 Tag/ABIs : default/armeabi-v7a

To create a new AVD using this target just run:

$ android create avd -n emulator-19 -t 1

The parameter -n helps us defining a name for our AVD. In this case emulator-19 will be the name of our AVD. This name is important because we need to tell Appium about it later in order to run our tests.

The parameter -t is used to select the target from the previous list. In our case: id: 1 or “android-19”.

Once the command is done we should get something similar to this output:

Auto-selecting single ABI armeabi-v7a
Android 4.4.2 is a basic Android platform.
Do you wish to create a custom hardware profile [no]no
Created AVD 'emulator-19' based on Android 4.4.2, ARM (armeabi-v7a) processor,
with the following hardware config:
hw.lcd.density=240
hw.ramSize=512
vm.heapSize=48

By default, the android tool creates the AVD directory inside ~/.android/avd/ (on Linux/Mac),

Finally, you can start the emulator by running:

$ emulator -avd <avd_name> [<options>]

Note that if you are using a real headless Ubuntu server you will get the the following error:

“SDL init failure, reason is: No available video device”

This means that it is not possible to detect a display connected to your machine. If you plan to run the android test on a headless server like in our case, then you can start the emulator without a graphical display. You can solve it by running the following:

$ emulator -avd emulator-19 -no-window

Now that we have the Android SDK installed and our emulator running, it is a good time to run the Appium configuration that we pointed earlier.

Open a new terminal instance and run the following commands from your workspace folder:

$ cd appium;
$ ./reset.sh —android  --verbose

if everything works fine you should be seeing this message:

Done, without errors.
---- reset.sh completed successfully ----

In our case, we had the following problem described in Stack Overflow for the Ubuntu version 14.04 64 bits:

"android-sdk-linux/build-tools/23.0.2/aapt": error=2, No such file or directory"

To fix this you are required to install two extra libraries by running:

$ sudo apt-get install lib32stdc++6 lib32z1

Then proceed by cleaning git and running the Appium configuration again:

$ git clean -dfx
$ git reset --hard
$ ./reset.sh —android  --verbose

In the end you should see the completion message:

Done, without errors.
---- reset.sh completed successfully ----

At this point you can start appium server by just running:

$ node .

Running Appium tests with python

The first requirement for this stage is to have your Android emulator and Appium up and running.

Appium supports different languages that you can use in order to write your tests. In our case, we want to use python and for doing so you need to have the appium-python-client installed in your python environment. Assuming that you have pip installed, you can do so by running:

$ pip install Appium-Python-Client

For demonstration purposes, we will be using the sample code that is available within the appium folder available in our workspace. The sample-code folder contains examples of Appium tests written in different languages plus a set of demo apps that we can use to get familiar with the Appium API.

Go to to the folder sample-code/examples/python/ and open the file android-simple.py. This file contains two tests that we will run towards one of the sample android apps.

The first thing we need to do is to edit the setUp method to indicate the right information about our environment. Replace the platformVersion for the platform used in your emulator, in our case this is 4.2.2 (API 19). Don’t forget to also replace the deviceName by the one you used to create your emulator. In our case this is “emulator-19”.

# Original android-simple.py

def setUp(self):
        desired_caps = {}
        desired_caps['platformName'] = 'Android'
        desired_caps['platformVersion'] = '4.2'
        desired_caps['deviceName'] = 'Android Emulator'
        desired_caps['app'] = PATH(
            '../../../sample-code/apps/ApiDemos/bin/ApiDemos-debug.apk'
        )

        self.driver = webdriver.Remote('http://localhost:4723/wd/hub', desired_caps)
# Modified android-simple.py

def setUp(self):
        desired_caps = {}
        desired_caps['platformName'] = 'Android'
        desired_caps['platformVersion'] = ‘4.2.2'
        desired_caps['deviceName'] = 'emulator-19'
        desired_caps['app'] = PATH(
            '../../../sample-code/apps/ApiDemos/bin/ApiDemos-debug.apk'
        )

        self.driver = webdriver.Remote('http://localhost:4723/wd/hub', desired_caps)

Once you do this you can just run the test and observe the interaction on the terminal. For running the test we recommend py.test installed in your python environment. If you don’t have it yet, just run the following:

$ pip install py.test

Then just run your python test:

$ py.test android-simple.py

If everything goes fine you should see the following lines at the very bottom of the shell trace:

=================================================================== 2 passed in 221.54 seconds ===================================================================
info: <-- DELETE /wd/hub/session/633463bd-f1c1-4c23-81f4-d61c6b9238ad 200 12182.584 ms - 76 {"status":0,"value":null,"sessionId":"633463bd-f1c1-4c23-81f4-d61c6b9238ad"}

This indicates that 2 tests were executed and they passed successfully.

Finally once the test has finished, if want to stop your emulator and Appium manually, then you can do so by running these commands respectively.

Stopping Android emulator:

$ adb emu kill

Stopping Appium: ctrl+c

Summary

In this tutorial we have shown how you can build your own test automation environment for Android by using Appium. We have described all the required steps to successfully install Appium in a fresh Ubuntu 14.04 server. Finally, we showed how simple it is to run Appium tests written in python.

In future tutorials we will review the Appium API and focus on writing specific tests for your apps.