Debugging and Testing Your Android Apps

Ken Jones and Marko Gargenta @Marakana

About Marko Gargenta

Marko Gargenta

1.1. Entrepreneur, Author, Speaker

Debugging Android Apps

Debugging Android Apps

Objectives of Android Debugging

This module provides an overview of some of the tools available in Android SDK that can help you with debugging your apps. By the end of this module you should have a general knowledge of what is available and how to use it.

The tools we’ll explore include:

LogCat

LogCat

The universal, most versatile way to track what is going on in your app.

Can be viewed via command line or Eclipse.

Logs can be generated both from SDK Java code, or low-level C code via Bionic libc extension.

Debugger

Debugger

Your standard debugger is included in SDK, with all the usual bells & whistles.

Traceview

Traceview

Traceview helps you profile you application and find bottlenecks. It shows execution of various calls through the entire stack. You can zoom into specific calls.

HierarchyViewer

HierarchyViewer

Hierarchy Viewer helps you analyze your User Interface.

Base UI tends to be the most “expensive” part of your application, this tool is very useful.

Summary of Android Debugging

In this module, you learned about some of the SDK tools, such as Logcat, Debugger, Traceview, and HierarchyViewer. You should be able to identify which one to use in what situation.

Android Testing

Android Testing

Android Test Framework

New Android Test Project Wizard
Android Test Projects

Android test projects are test suites based on JUnit

  • Android provides a set of JUnit extensions designed to test Android components such as Activities, Services, and Content Providers
  • You can use plain JUnit to test an auxiliary class that doesn’t call the Android API
Note The Android testing API supports only JUnit 3 capabilities, not JUnit 4. For example, test methods must be named starting with test rather than annotated with @Test.
Other Android Test Tools

Other tools provided by the SDK that you can use for for testing include:

  • UI/Application Exerciser Monkey, a command-line tool for stress-testing UIs by sending pseudo-random events to a device
  • The monkeyrunner tool, a Python API for writing programs that control an Android device or emulator from outside of Android code
  • The AVD emulator console

Android Test Project

Android tests, like Android applications, are organized into projects.

Android Test Case Classes

All Android test classes are in the android.test package. Some auxiliary classes are in sub-packages.

Additional General-Purpose Asserts

The Android SDK includes the MoreAsserts class, which defines a variety of assert methods beyond those provided by JUnit 3, including:

Android also provides overloaded versions of these methods that take an additional String message as their first parameter to provide more meaningful reporting in case of failures.

Additional View-Related Asserts

To support Activity testing, the ViewAsserts class provides several asserts for testing Views, including:

Android also provides overloaded versions of these methods that take an additional String message as their first parameter to provide more meaningful reporting in case of failures.


An example of using assertOnScreen():

ViewAsserts.assertOnScreen(view1.getRootView(), view2);

Mock Object Classes

You can completely or partially isolate the application component under test through the use of mock objects.

The mock object classes are contained in the android.test.mock package. The classes provided are:

Creating an Android Test Project in Eclipse

New Android Test Project Wizard

To create a test project in Eclipse:

  1. In Eclipse, select File ⇒ New ⇒ Other to open the Select a Wizard dialog.

  2. In the dialog, expand the entry for Android, then select Android Test Project and click Next to display the New Android Test Project wizard.

  3. Next to Test Project Name, enter a name for the project. A typical convention is to append "Test" to the project name for the application under test.

  4. In the Content panel, examine the suggested Location to the project and change if desired.

  5. In the Test Target panel, set An Existing Android Project, click Browse, then select your Android application from the list. You now see that the wizard has completed the Test Target Package, Application Name, and Package Name fields for you.

  6. In the Build Target panel, select the Android SDK platform that the application under test uses.

  7. Click Finish to complete the wizard.

The Test Project Manifest File

As the Android test project creates an application that is installed on the test device/emulator, it must have a manifest file.

Activity Testing: Activity Test Classes

In practice, most Activity test cases are derived from:

ActivityInstrumentationTestCase2

Designed to do functional testing of one or more Activities in an application, using a normal system infrastructure

ActivityUnitTestCase

Designed to test a single Activity in isolation. Before you start the Activity, you can inject a mock Context or Application, or both.

SingleLaunchActivityTestCase

Designed for testing an activity that runs in a launch mode other than standard. It invokes setUp() and tearDown() only once, instead of once per test method call. It does not allow you to inject any mock objects.

Overriding the Base Activity Test Class

When creating an Activity test case derived from any of the Activity Test Classes, you must provide a no-argument constructor.

Managing Activity Lifecycle and the Instrument Class

Android instrumentation is a set of control methods or "hooks" in the Android system.

The getActivity() method returns the Activity under test, starting it if necessary.

The InstrumentationTestCase class provides a getInstrumentation() method, which returns an Instrumentation object, which provides other methods from controlling an Activity, such as invoking its lifecycle methods. For example:

Turning Off Touch Mode

To control the emulator or a device with key events you send from your tests, you must turn off touch mode.

To turn off touch mode:

Generating Touch Events

The TouchUtils class provides many static methods for simulating touch events in the Activity. These include:

Sending Key Events

The InstrumentTestCase class provides methods for sending key events to the target Activity:

public void sendKeys (String keysSequence)

Sends a series of key events through instrumentation and waits for idle. The sequence of keys is a string containing the key names as specified in KeyEvent, without the KEYCODE_ prefix. For instance:

sendKeys("DPAD_LEFT A B C DPAD_CENTER");

Each key can be repeated by using the N* prefix. For instance, to send two KEYCODE_DPAD_LEFT, use the following:

sendKeys("2*DPAD_LEFT");
public void sendKeys (int… keys)

Sends a series of key events through instrumentation and waits for idle. For instance:

sendKeys(KEYCODE_DPAD_LEFT, KEYCODE_DPAD_CENTER);
public void sendRepeatedKeys (int… keys)

Sends a series of key events through instrumentation and waits for idle. Each key code must be preceded by the number of times the key code must be sent. For instance:

sendRepeatedKeys(1, KEYCODE_DPAD_CENTER, 2, KEYCODE_DPAD_LEFT);

Testing on the UI Thread

An application’s Activities run on the application’s UI thread (also known as the looper thread).

The test application runs in a separate thread in the same process as the application under test.

The TouchUtils methods and the InstrumentTestCase.sendKeys methods have been written to send these events to the UI thread safely.

To otherwise manipulate the UI, you must explicitly execute that code in the UI thread. There are two ways to do so:

Running Tests from Eclipse

Android Test Results in Eclipse

In Eclipse with ADT, you run a test application as an “Android JUnit test” rather than a regular Android application.

To run the test application as an Android JUnit test, in the Package Explorer right-click the test project and select Run As ⇒ Android JUnit Test.

The ADT plugin then launches the test application and the application under test on a the target emulator or device. When both applications are running, the testing framework runs the tests and reports the results in the JUnit view of Eclipse, which appears by default as a tab next to the Package Explorer.

Running Tests from the Command Line

Service Testing

ServiceTestCase extends the JUnit TestCase class with with methods for testing application permissions and for controlling the application and Service under test.

ServiceTestCase defers initialization of the test environment until you call ServiceTestCase.startService() or ServiceTestCase.bindService().

The setUp() method for ServiceTestCase is called before each test.

The methods setApplication() and setContext(Context) allow you to set a mock Context or mock Application (or both) for the Service, before you start it.

Content Provider Testing

You test a Content Provider with a subclass of ProviderTestCase2.

The ProviderTestCase2 constructor performs several important initialization steps for creating an isolated test environment.

The ProviderTestCase2 constructor creates an IsolatedContext object that allows file and database operations but stubs out other interactions with the Android system.

The constructor then creates a MockContentResolver to use as the resolver for the test.

Lastly, the constructor creates an instance of the provider under test.

Application Class Testing

You use the ApplicationTestCase test case class to test the setup and teardown of Application objects.

The test case can be useful in verifying that the <application> element in the manifest file is correctly set up.

Note This test case does not allow you to control testing of the components within your application package.

Stress Testing with the UI/Application Exerciser Monkey

30.1. What is the Monkey?

The Monkey is a command-line tool that you can run on an emulator or physical device to perform a stress test.

While executing, the Monkey monitors for three special conditions, which it can then handle:

Tip See the UI/Application Exerciser Monkey section of the Android Developer’s Guide for more information on the Monkey.

30.2. Basic Use of the Monkey

To launch the Monkey use adb shell to invoke the monkey command on the device or emulator:

adb shell monkey [options] <event-count>

With no options specified, the Monkey sends events to any (and all) packages installed on your target.

30.3. Controlling Monkey Event Generation

The monkey command supports options for adjusting the percentage of different event types generated by the Monkey:

--pct-touch <percent>

A down-up event in a single place on the screen

--pct-motion <percent>

A down event somewhere on the screen, a series of pseudo-random movements, and an up event

--pct-trackball <percent>

One or more random trackball movements, sometimes followed by a click

--pct-nav <percent>

Up/down/left/right, as input from a directional input device

--pct-majornav <percent>

Navigation events that typically cause actions within your UI, such as the center button in a 5-way pad, the back key, or the menu key

--pct-syskeys <percent>

Keys such as Home, Back, Start Call, End Call, or Volume controls

--pct-appswitch <percent>

Activity launches via a startActivity() call

--pct-anyevent <percent>

Other types of events such as keypresses and other less-used buttons on the device

30.4. Controlling Monkey Debug Behavior

The money command supports other options to change its default behavior in response to exceptions, timeouts, and crashes, including:

--ignore-crashes

Ignore application crashes and unhandled exceptions, rather than terminating event generation

--ignore-timeouts

Ignore application not responding conditions, rather than terminating event generation

--ignore-security-exceptions

Ignore permission errors, rather than terminating event generation

--kill-process-after-error

Kill the process after an error, rather than leaving it running after the test

--wait-dbg

Stop the Monkey from executing until a debugger is attaches to the process

Other Android Testing Tools

31.1. The monkeyrunner Tool

The monkeyrunner tool provides a Python API for writing programs that control an Android device or emulator to automate actions such as:

The monkeyrunner tool supports:

See the monkeyrunner section of the Android Developer’s Guide for more information on the monkeyrunner.

Note The monkeyrunner tool is not related to the UI/Application Exerciser Monkey (also known as the Monkey tool), which is used for stress testing.

31.2. An Example monkeyrunner Script

The following script demonstrates several monkeyrunner capabilities:

# Imports the monkeyrunner modules used by this program
from com.android.monkeyrunner import MonkeyRunner, MonkeyDevice

# Connects to the current device, returning a MonkeyDevice object
device = MonkeyRunner.waitForConnection()

# Installs the Android package. Notice that this method returns a boolean, so you can test
# to see if the installation worked.
device.installPackage('myproject/bin/MyApplication.apk')

# sets a variable with the package's internal name
package = 'com.example.android.myapplication'

# sets a variable with the name of an Activity in the package
activity = 'com.example.android.myapplication.MainActivity'

# sets the name of the component to start
runComponent = package + '/' + activity

# Runs the component
device.startActivity(component=runComponent)

# Presses the Menu button
device.press('KEYCODE_MENU', MonkeyDevice.DOWN_AND_UP)

# Takes a screenshot
result = device.takeSnapshot()

# Writes the screenshot to a file
result.writeToFile('myproject/shot1.png','png')

31.3. Robotium

The Robotium test framework extends the basic JUnit-based Android test framework to perform more black-box and feature testing. Features include the ability to develop and run tests:

For more information on Robotium, visit the project’s home page at http://robotium.org

Summary

Thank you

Thank you!

Marko Gargenta, Ken Jones and the Marakana Team

@MarkoGargenta

Slides & video of this presentation is available at Marakana.com

(c) Marakana.com

/

#