Strategies for DroidMate-2: A Platform for Android Test Generation.
ISSTA'19 paper: Learning User Interface Element Interactions
The tool can be downloaded to any directory.
In this document we name the directory where the tool is located as <DM>
By default input apks should be located in <DM>/apks
and the output will be store in <DM>/out
DM-2-Bandits is built on top of DroidMate-2 and automatically downloads all dependencies from JitPack and Maven Central.
It requires both JDK and Android SDK to be installed and their respective environment variables JAVA_HOME
and ANDROID_HOME
to be configured.
Here is a link with detailed about how to install and the JDK and Android SDK.
The tool is also integrated into the Travis-CI, its configuration file contains all commands used to configure and execute it.
In case of trouble compiling the tool, have a look at the DM-2 wiki
The tool requires a device or emulator to be executed and the device has to be recognized by the adb devices
command.
The emulator or device must be connected before executing the tool.
We don't ship a device emulator with the tool to facilitate its integration on different setups, such as physical devices, preferred emulator or external device farms.
The tool can be used with an emulator.
The Android Virtual Device (AVD) emulator is part of the SDK.
Google provides the following tutorial on how to create a virtual device using Android Studio and this tutorial to start it from the command line.
We mainly use Nexus 5X API 25 or Google Pixel XL API 26.
Check DM-2 list of supported device models.
on <DM>
folder execute /gradlew clean build
(Linux/OSX) or gradlew.bat clean build
(Windows)
The Gradle wrapper will automatically download all necessary dependencies
To confirm that everything worked fine execute:
./gradlew run --args="--help"
It will list all available configuration parameters.
Apks for testing can be downloaded from F-Droid or alternative app stores, such as ApkPure.
The tool is executed in 2 steps: instrumentation and exploration.
Instrumentation recompile the APK with log statements so that we can monitor the coverage during testing. Exploration executes the app and interacts with it.
By default both steps search for apks in the <DM>/apks
directory.
Also, the instrumentation step produces its output in the <DM>/apks
directory, while the exploration step stores its results in the <DM>/out/droidMate
directory.
Please note that the output folder is cleaned after each exploration, if you sequentially execute multiple experiments your results will be overwritten.
For the tool to obtain coverage, the apps should first be instrumented.
on <DM>
folder execute the command below to instrument an app (it will take the first app from the <DM>/apks
folder).
./gradlew run --args="--ExecutionMode-explore=false --ExecutionMode-coverage=true"
Once the instrumentation is complete it produces 2 files:
- Instrumented APK
- List of instrumented statements
Before executing an exploration, remove the original apk file from the input folder.
To run the experiment with the baseline strategy for 100 clicks, on <DM>
folder execute:
./gradlew run --args="-fps true --StatementCoverage-enableCoverage=true --Selectors-randomSeed=0 --Selectors-actionLimit=100"
To run the experiment with the baseline strategy for 100 clicks, on <DM>
folder execute:
./gradlew run --args="-fpsh true --StatementCoverage-enableCoverage=true --Selectors-randomSeed=0 --Selectors-actionLimit=100"
To run the experiment with the baseline strategy for 100 clicks, on <DM>
folder execute:
./gradlew run --args="-e true --StatementCoverage-enableCoverage=true --Selectors-randomSeed=0 --Selectors-actionLimit=100"
To run the experiment with the baseline strategy for 100 clicks, on <DM>
folder execute:
./gradlew run --args="-eh true --StatementCoverage-enableCoverage=true --Selectors-randomSeed=0 --Selectors-actionLimit=100"
To run the experiment with the baseline strategy for 100 clicks, on <DM>
folder execute:
./gradlew run --args="-t true --StatementCoverage-enableCoverage=true --Selectors-randomSeed=0 --Selectors-actionLimit=100"
To run the experiment with the baseline strategy for 100 clicks, on <DM>
folder execute:
./gradlew run --args="-th true --StatementCoverage-enableCoverage=true --Selectors-randomSeed=0 --Selectors-actionLimit=100"
Note: The instrumentation keeps the original (non-instrumented) app in the same location, to run only the version with coverage move the original apk to another folder.
The results are by default stored in the <DM>/out/droidMate
directory.
The most significant elements of the output folder are:
coverage
: contains the statements reached in each exploration action. This data can be compared against the original set of instrumented statements to obtain coverage.model
: contains the DM-2 model of the app, with all performed actions (trace*.csv
) as well as all observedstates
andwidgets
.log
: Copy of the device logcat during exploration.
For the paper experiments we used only the reached statements from the <DM>/out/droidMate/coverage
.
If the coverage folder is empty you are executing an apk which has not been instrumented. Please check Step 1
To list all available parameters, run with --help
./gradlew run --args="--help"
To import Dm-2 bandits on another project built on top of the DroidMate-2 platform follow the Jitpack instructions
If you see the following error message:
14:49:43 WARN [main @coroutine#1] o.droidmate.command.ExploreCommand initial fetch (warnIfNotHomeScreen) failed
java.lang.IllegalStateException: Error: Displayed Windows could not be extracted [DisplayedWindow(w=AppWindow(windowId=969, pkgName=com.android.systemui, hasInputFocus=false, hasFocus=false, boundaries=0:0:1440:84), initialArea=[Rect(0, 0 - 1440, 84)], rootNode=null, isKeyboard=false, layer=1, bounds=Rect(0, 0 - 1440, 84), windowType=3, isLauncher=false)]
at org.droidmate.uiautomator2daemon.uiautomatorExtensions.UiAutomationEnvironment.getDisplayedWindows(UiAutomationEnvironment.kt:191)
at org.droidmate.uiautomator2daemon.uiautomatorExtensions.UiAutomationEnvironment$getDisplayedWindows$1.invokeSuspend(Unknown Source)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:32)
at kotlinx.coroutines.ResumeModeKt.resumeMode(ResumeMode.kt:67)
at kotlinx.coroutines.DispatchedKt.resume(Dispatched.kt:272)
at kotlinx.coroutines.DispatchedKt.dispatch(Dispatched.kt:261)
at kotlinx.coroutines.CancellableContinuationImpl.dispatchResume(CancellableContinuationImpl.kt:218)
at kotlinx.coroutines.CancellableContinuationImpl.resumeImpl(CancellableContinuationImpl.kt:227)
at kotlinx.coroutines.CancellableContinuationImpl.resumeUndispatched(CancellableContinuationImpl.kt:299)
at kotlinx.coroutines.EventLoopImplBase$DelayedResumeTask.run(EventLoop.kt:298)
at kotlinx.coroutines.EventLoopImplBase.processNextEvent(EventLoop.kt:116)
at kotlinx.coroutines.BlockingCoroutine.joinBlocking(Builders.kt:76)
at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking(Builders.kt:53)
at kotlinx.coroutines.BuildersKt.runBlocking(Unknown Source)
at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking$default(Builders.kt:35)
at kotlinx.coroutines.BuildersKt.runBlocking$default(Unknown Source)
at org.droidmate.uiautomator2daemon.UiAutomator2DaemonDriver.executeCommand(UiAutomator2DaemonDriver.kt:48)
at org.droidmate.uiautomator2daemon.UiAutomator2DaemonServer.onServerRequest(UiAutomator2DaemonServer.kt:42)
at org.droidmate.uiautomator2daemon.UiAutomator2DaemonServer.onServerRequest(UiAutomator2DaemonServer.kt:33)
at org.droidmate.uiautomator2daemon.Uiautomator2DaemonTcpServerBase$ServerRunnable.run(Uiautomator2DaemonTcpServerBase.java:145)
at java.lang.Thread.run(Thread.java:764)
It means that DM-2 could not connect to the accessibility service on the device.
Please restart the device and try the exploration again.
If you see a NoAndroidDevicesFoundException
please check your device connection with the command adb devices
.
A device should be identified by ADB to be used in DM.
If you are experiencing issues installing the emulator, such as:
[4601566656]:ERROR:android/android-emu/android/qt/qt_setup.cpp:28:Qt library not found at ../emulator/lib64/qt/lib
Could not launch '/usr/local/Caskroom/android-sdk/4333796/tools/../emulator/qemu/darwin-x86_64/qemu-system-i386': No such file or directory
The Android emulator require special host characteristics, such as qemu (e.g. when running on Docker) and a graphics card (to use hardware accelerated rendering). If you are using a virtualized environment (such as Docker), try it in your host OS. Otherwise, have a look at this stack overflow thread.
Exception in thread "main" org.droidmate.device.android_sdk.AdbWrapperException: Executing 'adb install' failed. Oh my.
at org.droidmate.device.android_sdk.AdbWrapper.installApk(AdbWrapper.kt:149)
at org.droidmate.device.AndroidDevice.installApk(AndroidDevice.kt:361)
at org.droidmate.device.AndroidDevice.reinstallUiAutomatorDaemon(AndroidDevice.kt:372)
at org.droidmate.device.deviceInterface.RobustDevice$reinstallUiAutomatorDaemon2.invokeSuspend(RobustDevice.kt:645)
at org.droidmate.device.deviceInterface.RobustDevice2.invokeSuspend(RobustDevice.kt:645)
at org.droidmate.device.deviceInterface.RobustDevice2.invokeSuspend(RobustDevice.kt:645)
at org.droidmate.device.deviceInterface.RobustDevicereinstallUiAutomatorDaemon2.invoke(RobustDevice.kt)
at org.droidmate.misc.Utils2.invoke(RobustDevice.kt)
at org.droidmate.misc.Utils2.invoke(RobustDevice.kt)
at org.droidmate.misc.UtilsCompanion.retryOnException(Utils.kt:57)
at org.droidmate.misc.UtilsCompanionCompanionCompanionretryOnException1.invokeSuspend(Utils.kt)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:32)
(...)
A problem occured while starting the on-device TCP server used to interact with the device. Please restart the device or emulator.
More customization instructions can be found on the DroidMate-2 project.