Skip to content

Android setup

Configure and run Android UI tests on Marathon Cloud.

Marathon Cloud supports native Android testing frameworks and cross-platform solutions. You can run tests written in Espresso, UIAutomator, Kakao, Kaspresso, and Flutter (via Patrol).

Terminal window
marathon-cloud run android \
--api-key $MARATHON_CLOUD_API_KEY \
--application app-debug.apk \
--test-application app-debug-androidTest.apk

Marathon Cloud executes standard Android instrumentation tests. The following frameworks are fully supported:

  • Espresso: The standard framework for Android UI testing.
  • UIAutomator: For cross-app functional UI testing.
  • Kakao/Kaspresso: DSL wrappers around Espresso for better readability and stability.
  • Cucumber: For behavior-driven development.
  • Flutter (Patrol): For testing Flutter applications with native features.

You must provide two APK files: the application under test and the instrumentation test APK.

  1. Open your terminal in the root of your Android project.

  2. Run the Gradle assembly tasks for both the app and the test app.

    Terminal window
    ./gradlew :app:assembleDebug :app:assembleDebugAndroidTest
  3. Locate the generated APKs in the build output directory. Typically, these are found at:

    • app/build/outputs/apk/debug/app-debug.apk
    • app/build/outputs/apk/androidTest/debug/app-debug-androidTest.apk
Terminal window
marathon-cloud run android \
--api-key YOUR_API_KEY \
--application path/to/app-debug.apk \
--test-application path/to/app-debug-androidTest.apk \
--os-version 15 \
--system-image google_apis

The examples below omit --api-key; the CLI reads it from MARATHON_CLOUD_API_KEY when the flag is absent.

Parameter Description
--os-version Android version: 8, 8.1, 9, 10, 11, 12, 13, 14, 15, 16, 17.
--system-image default, google_apis, or google_apis_playstore.
--arch amd64 (default) or arm64. Pick arm64 when the app ships native libraries without an x86_64 ABI or you want to match production hardware.
--device Device type ID from marathon-cloud devices android. Use watch or tv for those form factors; omit for a phone. See supported devices.

Not every combination is valid, and the CLI rejects invalid ones before uploading:

  • Android 15, 16, 17 require google_apis or google_apis_playstore.
  • Android 8 to 9 require google_apis.
  • watch requires google_apis and Android 11, 13, or 15; tv requires google_apis and Android 10 to 14.
  • arm64 requires Android 9 or later. default images are arm64 only; use google_apis or google_apis_playstore for amd64.

--flavor is deprecated; only native instrumentation tests are supported and the flag is ignored.

--application-bundle replaces --application + --test-application for multi-module projects and can be repeated to run several modules in one run. --library-bundle is for library modules that have a test APK but no app APK.

Terminal window
marathon-cloud run android \
--application-bundle app/build/outputs/apk/debug/app-debug.apk,app/build/outputs/apk/androidTest/debug/app-debug-androidTest.apk \
--application-bundle feature/build/outputs/apk/debug/feature-debug.apk,feature/build/outputs/apk/androidTest/debug/feature-debug-androidTest.apk
Terminal window
marathon-cloud run android \
--library-bundle mylib/build/outputs/apk/androidTest/debug/mylib-debug-androidTest.apk

Camera emulation requires a google_apis or google_apis_playstore image. --mock-location is a switch and takes no value.

Terminal window
marathon-cloud run android \
--application app-debug.apk \
--test-application app-debug-androidTest.apk \
--os-version 15 \
--system-image google_apis \
--mock-location \
--front-camera emulated \
--back-camera virtualscene

Instrumentation arguments and pulled files

Section titled “Instrumentation arguments and pulled files”

--instrumentation-arg is repeatable and passed through to the instrumentation runner. --pull-files copies files off the device after each batch into device-files.tar in the artifacts; the path is relative to the chosen root.

Terminal window
marathon-cloud run android \
--application app-debug.apk \
--test-application app-debug-androidTest.apk \
--code-coverage \
--instrumentation-arg "debug=true" \
--instrumentation-arg "clearPackageData=true" \
--pull-files "EXTERNAL_STORAGE:screenshots" \
--pull-files "APP_DATA:files/reports"

ROOT is EXTERNAL_STORAGE (/sdcard) or APP_DATA (the app’s private data directory). Files with the same path from different devices overwrite each other in the archive.

--isolated puts every test in its own batch so no test shares a batch with another. Use it to confirm whether a failure depends on tests that ran before it; it makes the run longer and more expensive. See batching.

Terminal window
marathon-cloud run android \
--application app-debug.apk \
--test-application app-debug-androidTest.apk \
--isolated

Marathon Cloud sizes the device pool to finish in about 15 minutes, which can mean many devices hitting your backend at once. If your tests share fixtures or your staging backend cannot take the load, cap the pool:

Terminal window
marathon-cloud run android \
--application app-debug.apk \
--test-application app-debug-androidTest.apk \
--concurrency-limit 4

Treat this as a stopgap; see limiting concurrency.

The command exits 1 if any test fails and 0 otherwise. Add --result-file result.json for a machine-readable summary and --output ./results to download JUnit XML and videos. See exit codes.