I recently fought the Android emulator a lot to get my UI tests to run automatically during the build of Rabbit Escape, so I thought I’d better write down what I did before I forget.
I already have tests that drive the Android UI (see e.g. SmokeTest.java – it’s not pretty, but it seems reliable, and it catches real problems) – this post is about how to run them automatically during our build.
Note that to run the Android emulator I’m fairly sure you need a windowing environment, so I don’t think this could be moved to a headless build server. If course, you could always fight some kind of framebuffer thing.
Here is the part of our Makefile that launches the tests:
android-smoke-tests: @echo ". Running Android smoke tests" ./build-scripts/android-start-emulator "android-8" "3.2in QVGA (ADP2)" ./build-scripts/android-test "free" "app-free-debug" ./build-scripts/android-test "" "app-paid-debug" ./build-scripts/android-stop-emulator
and here is ./build-scripts/android-start-emulator – it starts up and emulator, waits for it to be ready, and unlocks its screen.:
#!/bin/bash set -x set -u set -e # Args TARGET="$1" # E.g. "android-8" DEVICE="$2" # E.g. "3.2in QVGA (ADP2)" # Setup ADB="${HOME}/Android/Sdk/platform-tools/adb" EMULATOR="${HOME}/Android/Sdk/tools/emulator" ANDROID="${HOME}/Android/Sdk/tools/android" NAME="rabbitescape-${TARGET}" TMP="/data/local/tmp" ${ANDROID} create avd \ --force \ --name "${NAME}" \ --target "${TARGET}" \ --abi "armeabi" \ --device "${DEVICE}" # Start the emulator ${EMULATOR} -avd "${NAME}" & # Wait for the device to boot and unlock it ${ADB} wait-for-device shell <${TMP}/zero getprop dev.bootcomplete > ${TMP}/bootcomplete while cmp ${TMP}/zero ${TMP}/bootcomplete; do { echo -n "." sleep 1 getprop dev.bootcomplete > ${TMP}/bootcomplete }; done echo "Booted." exit ENDSCRIPT echo "Waiting 30 secs for us to be really booted" sleep 30 echo "Unlocking screen" ${ADB} shell "input keyevent 82"
Now here is android-test – it launches the JUnit test code on the running emulator::
#!/bin/bash set -x set -u set -e PKGSUFFIX="$1" # E.g. "free" APKNAME="$2" # E.g. "app-free-debug" APPID="net.artificialworlds.rabbitescape${PKGSUFFIX}" TESTAPPID="net.artificialworlds.rabbitescape${PKGSUFFIX}.test" APK="rabbit-escape-ui-android/app/build/outputs/apk/${APKNAME}.apk" TESTAPK="rabbit-escape-ui-android/app/build/outputs/apk/${APKNAME}-androidTest.apk" ADB="${HOME}/Android/Sdk/platform-tools/adb" DIR="/data/local/tmp/${APPID}" TESTDIR="/data/local/tmp/${TESTAPPID}" function run_test() { TMPFILE=$(mktemp) ${ADB} shell am instrument \ -w \ -r \ -e class "$1" \ "${TESTAPPID}/android.test.InstrumentationTestRunner" \ | tee ${TMPFILE} egrep "OK (.* tests?)" ${TMPFILE} } ${ADB} push "${APK}" "${DIR}" ${ADB} push "${TESTAPK}" "${TESTDIR}" ${ADB} shell pm install -r "${DIR}" ${ADB} shell pm install -r "${TESTDIR}" run_test rabbitescape.ui.android.DialogsTest run_test rabbitescape.ui.android.SmokeTest run_test rabbitescape.ui.android.TestAndroidConfigUpgradeTo1
And here is android-stop-emulator – it shuts down the emulator:
#!/bin/bash set -x set -u echo -e "auth $(cat ~/.emulator_console_auth_token)\nkill" \ | telnet localhost 5554 echo "Emulator stopped."