Testing C++ Code with UnitTest++ on Android
I’m sure you’ve come across a unit testing framework or two. At least with me, the concept of running automated tests to make sure that changes don’t break my code, caught on very quickly.
My favourite unit testing framework for C++ code is UnitTest++, which I’ve been using for a while now. Because of recently announced additional features in UnitTest++ that make it easier to run tests on Android, I’m outlining here the steps to get your unit tests running on Google’s mobile operating system.
Why Use a C++ Unit Testing Framework on Android?
Apps on Android are written in Java, but Google also offers the Android Native Development Kit (NDK), which allows you to extend your Java app with code written in C/C++.
This makes sense when you develop a game: not only does C/C++ code execute faster than Java, but you can also use the same code on every platform that supports C/C++ and OpenGL. In the mobile space, this includes iPhone, Android, WebOS, and Windows Phone 6.5, but not BlackBerry (uses Java) and Windows Phone 7 (C#). Mac OS and Windows on desktop computers can be supported as well, of course.
UnitTest++ is being developed by Noel Llopis and Charles Nicholson; themselves active game developers. There’s nothing game-specific in UnitTest++, but games are one of those application domains where C++ is still the most popular choice for programmers.
If you are like me and develop a cross-platform codebase in C++, running your unit tests on Android makes sure that no platform-specific bugs sneak into your code.
Installing the Android SDK
To start working with the NDK, you first have to install the latest Android SDK. The NDK contains the compilers and tools for building C/C++ code, but you’ll need the SDK to add a small Java app and package it with the native code so the bundle can be run on an Android emulator or device.
All of Google’s tools support Windows, Mac OS X, and Linux, so you shouldn’t have problems following my steps on either operating system.
To install the Android SDK, I suggest you follow Google’s installation guide. I’m assuming here that you want to use Eclipse as your IDE, so follow the bits where it mentions the Android Development Tools (ADT) plugin for Eclipse in Google’s description. In the end you should have installed the SDK Starter Package, Eclipse, ADT, and also downloaded one or more Android platforms.
If you are new to Android development, it’s a good idea to follow the Hello World tutorial to make sure everything is installed properly and you also have an Android Virtual Device configured. That’s the emulator that runs your apps before you install them on a real device.
Installing the Android NDK
The Android NDK is a download that doesn’t need installation and you can simply extract the contents of the zip file to a folder of your choice (I keep mine next to the SDK). Windows users will also need Cygwin in order to get gnumake and bash; both of which are used by the NDK’s build environment. More information can be found here.
Downloading the Example Project
I combined all the files required for building and running UnitTest++ into one zip file so you can get started right away. This zip file includes a version of UnitTest++, a simple Android Java app to run your unit tests, and some bits of code to glue the two together.
I suggest you download this file now and unzip it to a folder, and I’ll explain the contents in more detail.
Using the Java Native Interface
C/C+ code compiled with the NDK produces a shared library that can be loaded by your Android app at run-time. In order to call code in this shared library from Java, you have to use the Java Native Interface (JNI).
Here is how I declared the entry point that my example Java app will use to execute the unit tests (you can find this code in src/com/example/unittestpp/UnitTestPP.java):
package com.example.unittestpp;
public class UnitTestPP extends Activity
{
public native String executeUnitTests();
}
Important here is that executeUnitTests() is tagged with the native keyword. JNI then maps executeUnitTests() to the following C function declaration:
jstring Java_com_example_unittestpp_UnitTestPP \ _executeUnitTests(JNIEnv* env, jobject thiz)
You can see how the package, class, and method name in Java are concatenated into a function name. This naming convention makes it possible for the Android system to find the right entry point in your shared library.
This is what the implementation of this function looks like (jni/UnitTestPP.cpp):
#ifdef __cplusplus
extern "C" {
#endif
jstring Java_com_example_unittestpp_UnitTestPP \
_stringFromJNI(JNIEnv* env, jobject thiz)
{
// Run all tests (same as UnitTest::RunAllTests()).
TestReporterStdout reporter;
TestRunner runner(reporter);
runner.RunTestsIf(Test::GetTestList(), NULL, True(), 0);
TestResults* testResults = runner.GetTestResults();
// Pass results back to Java for display.
char result[128];
if (testResults->GetFailedTestCount() > 0)
{
sprintf(result, "Final results: failure\n" \
"%d out of %d test(s) failed (%d failure(s)).",
testResults->GetFailedTestCount(),
testResults->GetTotalTestCount(),
testResults->GetFailureCount());
}
else
{
sprintf(result, "Final results: success\n" \
"%d test(s) passed.", testResults->GetTotalTestCount());
}
return env->NewStringUTF(result);
}
#ifdef __cplusplus
}
#endif
Because this function is located in a file ending with .cpp, the NDK will consider the contents C++ code. The JNI, however, expects C-style function entries so you have to surround the function with extern "C" {}. This makes sure the function can be called like a C function, even if it’s containing C++ code.
The code itself does the following: A TestRunner is created that executes all the unit tests the framework can find (I’ve included a few simple tests at the top of jni/UnitTestPP.cpp). After the unit tests end, TestRunner also provides statistics about the successful and failed tests. This information is appended to a character array and finally passed back to the Java calling code in the return statement. NewStringUTF() must be used here to convert the C character array to a Java String object.
Building UnitTest++ for Android
To build C++ code with the Android NDK, you’ll need to provide a file called Android.mk that lists the files to compile and their build options. This is what this file looks like for UnitTest++ (you can find it in the jni folder):
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := unittestpp LOCAL_C_INCLUDES := \ $(LOCAL_PATH)/../unittestpp-read-only \ $(LOCAL_PATH)/../unittestpp-read-only/src \ $(LOCAL_PATH)/../unittestpp-read-only/src/Posix LOCAL_SRC_FILES := \ UnitTestPP.cpp \ ../unittestpp-read-only/src/AssertException.cpp \ ../unittestpp-read-only/src/Checks.cpp \ ../unittestpp-read-only/src/CurrentTest.cpp \ ../unittestpp-read-only/src/DeferredTestReporter.cpp \ ../unittestpp-read-only/src/DeferredTestResult.cpp \ ../unittestpp-read-only/src/MemoryOutStream.cpp \ ../unittestpp-read-only/src/ReportAssert.cpp \ ../unittestpp-read-only/src/Test.cpp \ ../unittestpp-read-only/src/TestDetails.cpp \ ../unittestpp-read-only/src/TestList.cpp \ ../unittestpp-read-only/src/TestReporter.cpp \ ../unittestpp-read-only/src/TestReporterStdout.cpp \ ../unittestpp-read-only/src/TestResults.cpp \ ../unittestpp-read-only/src/TestRunner.cpp \ ../unittestpp-read-only/src/TimeConstraint.cpp \ ../unittestpp-read-only/src/XmlTestReporter.cpp \ ../unittestpp-read-only/src/Posix/SignalTranslator.cpp \ ../unittestpp-read-only/src/Posix/TimeHelpers.cpp LOCAL_CFLAGS := \ -DUNITTEST_POSIX -DNULL=0 \ -DUNITTEST_NO_DEFERRED_REPORTER \ -DUNITTEST_NO_EXCEPTIONS include $(BUILD_SHARED_LIBRARY)
Android.mk is executed as part of a generic makefile provided by the NDK, so you only need to set some makefile variables with project-specific settings. These settings include:
LOCAL_MODULE: The name of your project, which will also be used for the name of the resulting shared library (libunittestpp.so).LOCAL_C_INCLUDES: A list of directories with your project’s include files.LOCAL_SRC_FILES: This is the list of all the source files to compile for your project including the JNI code (UnitTestPP.cpp) and the UnitTest++ sources (located inunittestpp-read-only/src).LOCAL_CFLAGS: A list of additional compiler flags.
The Android NDK only supports a small set of APIs; it doesn’t include the STL, doesn’t support exceptions, and only provides a a subset of the C standard library.
To get UnitTest++ to compile despite these restrictions, I had to define UNITTEST_NO_DEFERRED_REPORTER to disable all deferred test reporters, such as XmlTestReporter, because those classes use stl::vector. I also disabled the use of exceptions in UnitTest++ by defining UNITTEST_NO_EXCEPTIONS (UnitTest++ then uses setjmp/longjmp instead.
A rather annoying problem was the lack of C++-style standard library headers. In C++, you can replace header includes such as #include <stdio.h> with #include <cstdio>. UnitTest++ makes ample use of this include style and modifying all source files would have been annoying. Fortunately, Android’s x86 environment does have those headers, so I just copied the missing files from NDK’s build/platforms/android-8/arch-x86/usr/include folder into the jni folder of the example project where the compiler can find them. The contents of those files are very simple, so you can just use these until Google fixes this issue.
Another change I had to do was to disable signal processing. (It might be possible to make this work, but I didn’t need it.) If you have a look in unittestpp-read-only/src/ExecuteTest.h, I commented out the line that mentions THROW_SIGNALS.
UT_TRY
({
// UNITTEST_THROW_SIGNALS_POSIX_ONLY
testObject.RunImpl();
})
With all the configuring done, you can now compile UnitTest++:
- Open a terminal and change into the
unittest++folder from the example project. (Windows user will need to start Cygwin’s version ofbashin a DOS box and then do the same.) - Run
../ndk-buildand press Return to build the code (ndk-buildis a shell program that’s located in the NDK’s top-level folder, but you have to ececute the script from within theuinttest++directory.
The compiled library with the name libunittestpp.so should now be in the libs/armeabi folder.
Creating an Android Java App
The shared library that includes UnitTest++ needs to be included in a standard Android Java app. I provided a simple Java project with only one Activity (src/com/example/unittestpp/UnitTestPP.java).
public class UnitTestPP extends Activity
{
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
/* Create a TextView and set its content. The text is
* retrieved by calling a native function.
*/
TextView tv = new TextView(this);
tv.setText(executeUnitTests());
setContentView(tv);
}
/* A native method that is implemented by the
* native library, which is packaged with this application.
*/
public native String executeUnitTests();
/* This is used to load the native library on application
* startup. The library has already been unpacked at
* installation time by the package manager.
*/
static {
System.loadLibrary("unittestpp");
}
}
This Android Activity has two important tasks: It loads the shared library with UnitTest++ and executes your unit tests.
The first task is achieved by calling System.loadLibrary("unittestpp"), where unittestpp is used to find the shared library with the name libunittestpp.so. Because this code is contained in a static block, it’s executed before any other method in this class is called.
The second task uses the JNI mapping that I have discussed previously. Calling executeUnitTests(), which is tagged with the keyword static, will call into the entry point that I defined in UnitTestPP.cpp. The string with the unit test results is then displayed on the screen with a TextView.
To import the Java project from the example:
- Open Eclipse and select File > New > Project…
- Select Android Project and click Next
- In the New Android Project dialog, enter “unittestpp” as project name
- Select Create project from existing source
- Find the unittest++ folder on your computer and enter it in the Location textfield
- Select Android 1.5 as the Build Target (minimum for NDK projects is API level 3)
- Click Finish
The project should now turn up in your project navigator. Make sure that libunittestpp.so turns up under libs/armeabi in the project navigation window. If it doesn’t, right click on the armeabi folder and click Refresh.

Eclipse will build the Android project for you automatically and also include libunittestpp.so in the installation file. To check if that has worked, copy bin/unittestpp.apk, give it the file ending .zip and have a look inside. The shared library should be in the lib/armeabi folder. Android’s application manager will automatically install the library on the emulator or device when you install the app.
Note: when you recompile the shared library, Eclipse doesn’t automatically realise that the project has changed. The easiest way to repackage the app is to make a small change to a comment in UnitTestPP.java and save the file. Eclipse will then rebuild the APK file and include the latest library.
Running the Unit Tests
To run the Java application with your unit tests:
- Select Run > Run Configurations…
- Select Android Application in the upcoming Run Configurations dialog
- Click the little icon on the left where it says New launch configuration when you mouse over the icon
- Enter a name for the configuration or accept the default one
- Select the unittestpp project with the Browse… button
- Click Apply and then Run
This should start the Android emulator with your app. If everything goes according to plan, you should eventually see the result of running your unit tests:

Updating to the Latest UnitTest++ Version
UnitTest++ hasn’t provided an official release for a while. Instead, you are supposed to download the latest code from its SVN code repository. If you want to update the UnitTest++ version that comes with the example project, simply run svn update in the unittestpp-read-only directory. Don’t forget to check if my modification of TestExecute.h has merged correctly.
Final Words
That’s it! Much of the complexity comes from using the Android NDK rather than from UnitTest++. Once you have set everything up, adding more tests should be much easier. Add some comments to this post if you get stuck.
No Comments
Trackbacks/Pingbacks
September 17th, 2010 at 02:12
[...] This post was mentioned on Twitter by Noel Llopis and tuan kuranes, Claus Höfele. Claus Höfele said: How to use @snappytouch and @c_nich's UnitTest++ to test your C++ code on Android http://bit.ly/c2q3eA #android #unittesting [...]