The Android framework contains several familiar and new architectural patterns. Fortunately, testing was not forgotten. In this post, we’ll develop a simple app test-first, exploring both functional and unit testing in Android. We’ll be using the latest Android API, 4.1, and working entirely from the command-line. All the code is available on github.
Install the Android SDK by following the instructions on the Android developer site.The SDK includes the
android command-line tool in the tools directory. We’ll use the
android command to create our projects and install our app on an emulator.
The SDK only includes basic Android tools, such as the
android command. We still need a version of the Android API and other various platform tools.
android sdk to load the Android SDK Manager. Select and install the Android SDK Platform-tools and Android 4.1 options. For convenience, add both the tools and platform-tools directories to your
Running Tests on Android
There are two ways to run Android tests:
- On a standard-JVM without any access to the Android framework.
- On an Android device (or emulator).
We’ll be running our tests the “Android way”, i.e. on an emulator. The obvious trade-off is speed. Our tests will run slower but, I feel more confident running tests in an environment similar to a production Android environment.
The Android SDK includes an emulator that runs Android Virtual Devices. An Android Virtual Device is an emulator configuration for a specific version of the Android API. The
android command can be used to create Android Virtual Devices.
An Android Virtual Device requires a name and a target (an Android platform).
android can be used to get a list of the available targets (Android APIs) we have installed.
We’ll use our sole Android 4.1 target and name our Android Virtual Device after our app and Android API version.
Code and Test Code Organization
We now have all the Android tools, a version of the Android API, and an Android Virtual Device to run on our emulator. We can now finally start writing code.
The first step we need to do is create an Android project and its separate test project. Again, we’ll use the
These two commands created our two projects side-by-side, in the same directory. Each project includes all the basic Android app configuration, as well as an initial activity (controller) class.
Starting with a High-level Functional Test
In Android, functional tests are integration tests. A functional test will usually represent a user story encompassing the interaction of several different objects throughout the system. We’ll start development of our simple app with a high-level, functional test.
To keep things simple, our app will consist of only two screens:
- A screen containing a form to submit a name.
- A following screen displaying a greeting using the submitting name.
We’ll use Robotium to write our functional test. Robotium is a popular Android testing library with a very clean and intuitive API. Let’s add it to our test project.
robotium requires making a change to our app’s manifest. Add the following element as a child of the root <manifest> element (see the robotium questions and answers for more information) in our non-test project’s AndroidManifest.xml file.
With Robotium configured, we can write our functional test:
Solo object, the test-driver, fills in an editable text field, clicks a button, and then expects to see a greeting. One important thing to note is that functional tests extend the poorly named
In order to run our functional test, we need to install our project and test project on our emulator. We’ll use the
emulator command from the Android SDK to start an emulator based on our previously created Android Virtual Device. The first time you run a new Android Virtual Device on an emulator, remember to unlock the emulator by dragging and dropping its lock icon onto the unlock icon. Also click around a bit on the emulator to ensure everything is ok.
create project and
create test-project generate an
ant build.xml file. We can use the build file’s
install target to build a debug package of our projects and install them on our running emulator.
test target for running tests, is also available.
Alright, our first failure leads us into the implementation.
Getting to Green
Views in Android can be specified using XML. Activity objects display these views and also handle user actions, e.g. tapping a button.
create project command created our first activity for us.
This default implementation is fine for now; we only need to change its layout. XMl layouts are declared in res/layout. Let’s modify the “main” layout to consist of an editable text field and a button.
After making this change, we need to re-install the app on our emulator. Then, we can re-run our functional test.
Our functional test ran further this time. It successfully filled in the editable text field and clicked the button; however, it failed to see a greeting. This failure could have been caused by a number of things. So, instead of working with just a high-level functional test, let’s drop down and unit test our activity.
Drilling Down to a Unit Test
Besides functional testing, the other type of testing Android advocates is unit testing. Activity unit tests in Android run decoupled from the framework, and are thus, true unit tests. This decoupling enables unit tests to run much faster than functional tests.
Here’s a sample unit test for our
Main activity. The test verifies that another activity is started when the “submit” button is pressed.
This lower-level unit test exercises the activity by directly accessing its view widgets. It ends by verifying the submitted name is passed along with the
Intent. One important thing to note is that unit tests extend the well-named
To run this unit test, we need to re-build the test project and install it on our emulator. Then, instead of running both tests with the
test target, we’ll run just this individual unit test.
To get this test passing, we need to add an event handler to our button’s click event and have it start a new activity.
Our button click handler uses an explicit intent to an undefined
Greeting activity. Let’s define this activity and add its configuration to our app’s manifest.
After building and installing our latest changes to our emulator, we can re-run our unit test.
With our unit test passing, we can come back up and re-run our higher-level functional test.
A Solid Foundation
While this post only explored activity testing in Android, there is also support for testing other Android components e.g., services and content providers. All the basic building blocks for effective testing are there. Hopefully Android developers, like Rubyists, will continue to practice and embrace testing. Only through testing will our tools continue to improve.