| name | running-instrumented-tests-via-adb |
| description | Use this skill to run instrumented Android tests directly through `adb shell am instrument -w -r` without going through Gradle. Covers the required `-w` (wait — REQUIRED for meaningful exit codes) and `-r` (raw output) flags, the `-e` argument table (`class`, `class#method`, `package`, `size`, `numShards`/`shardIndex`, `debug`, `annotation` / `notAnnotation`, `listener`, `clearPackageData`, `targetInstrumentation`), the canonical runners `AndroidJUnitRunner` and `AndroidTestOrchestrator`, the orchestrator wrapping pattern (target = orchestrator, `-e targetInstrumentation <pkg>/<runner>`), and the output framing (`INSTRUMENTATION_STATUS_CODE` 1=start, 0=ok, -1=error, -2=failure, -3=ignored, -4=assumption-failure; `INSTRUMENTATION_RESULT`; `INSTRUMENTATION_CODE`). Use when the user mentions `am instrument`, `AndroidJUnitRunner`, "run tests from CI without Gradle", "Orchestrator", `clearPackageData`, `targetInstrumentation`, exit codes from `am instrument`, or `INSTRUMENTATION_STATUS_CODE`. |
| license | Apache-2.0. See LICENSE for complete terms. |
| metadata | {"author":"Jaewoong Eum (skydoves)","keywords":["am-instrument","AndroidJUnitRunner","AndroidTestOrchestrator","clearPackageData","targetInstrumentation","INSTRUMENTATION_STATUS_CODE","test-sharding","numShards","shardIndex","run-listener"]} |
Running Instrumented Tests via ADB — am instrument without Gradle
adb shell am instrument is the underlying command Gradle invokes; running it directly is the right tool for CI scripts that already manage their own APKs, for sharding fan-out across many devices, and for tight-loop debugging of a single test method. The pitfall most CI scripts fall into: omitting -w, which makes the exit code meaningless. The second-most-common pitfall: flipping the orchestrator-target relationship.
When to use this skill
- The user wants a single test method to run from a script:
adb shell am instrument -w -r -e class com.example.MyTest#myMethod ....
- The user wants to shard a test suite across N devices using
numShards / shardIndex.
- The user is wiring AndroidX Test Orchestrator with
clearPackageData true and gets the target/targetInstrumentation order confused.
- The user's CI script reports green when tests actually failed because
$? is 0 even though INSTRUMENTATION_STATUS_CODE: -2 shows a failure.
- The user wants the on-device runner to wait for a debugger attach before running tests.
When NOT to use this skill
- The user wants to install or reset the app under test — use
../../apps/installing-and-managing-apps/SKILL.md.
- The user wants to choose a device, wait for boot, or set up Wi-Fi debugging — use
../../devices/connecting-to-devices/SKILL.md and ../../devices/connecting-over-wifi/SKILL.md.
- The user is writing the JUnit4 /
AndroidJUnit4 test class itself — use ../../../instrumentation/runner/running-instrumented-tests-with-androidjunit4/SKILL.md.
- The user wants Gradle to do the run for them (
./gradlew connectedDebugAndroidTest) — that path also reads instrumentation runner args from testInstrumentationRunnerArguments.
Prerequisites
- App APK installed (
com.example.app) and test APK installed (com.example.app.test) — see ../../apps/installing-and-managing-apps/SKILL.md.
- The test APK was built with
-t allowed (android:testOnly="true").
- For Test Orchestrator:
androidx.test.orchestrator APK installed (typically via androidTestUtil("androidx.test:orchestrator:1.6.1") and adb install -r androidx.test.orchestrator.apk).
- Device in
device state and animations disabled for stable runs (see docs/CORPUS.md §I.6 hermetic test setup).
Workflow
Patterns
Pattern: WRONG vs RIGHT — exit code without -w
adb shell am instrument -r \
com.example.app.test/androidx.test.runner.AndroidJUnitRunner
echo $?
output=$(adb shell am instrument -w -r \
com.example.app.test/androidx.test.runner.AndroidJUnitRunner)
if echo "$output" | grep -qE 'INSTRUMENTATION_STATUS_CODE: -[12]$'; then
echo "FAILED"; exit 1
fi
Pattern: WRONG vs RIGHT — orchestrator target/targetInstrumentation flip
adb shell am instrument -w -r \
-e clearPackageData true \
-e targetInstrumentation androidx.test.orchestrator/.AndroidTestOrchestrator \
com.example.app.test/androidx.test.runner.AndroidJUnitRunner
adb shell am instrument -w -r \
-e clearPackageData true \
-e targetInstrumentation com.example.app.test/androidx.test.runner.AndroidJUnitRunner \
androidx.test.orchestrator/.AndroidTestOrchestrator
Pattern: WRONG vs RIGHT — sharding across two devices
adb -s emulator-5554 shell am instrument -w -r -e numShards 2 -e shardIndex 0 \
com.example.app.test/androidx.test.runner.AndroidJUnitRunner &
adb -s emulator-5554 shell am instrument -w -r -e numShards 2 -e shardIndex 1 \
com.example.app.test/androidx.test.runner.AndroidJUnitRunner &
wait
adb -s emulator-5554 shell am instrument -w -r -e numShards 2 -e shardIndex 0 \
com.example.app.test/androidx.test.runner.AndroidJUnitRunner &
adb -s emulator-5556 shell am instrument -w -r -e numShards 2 -e shardIndex 1 \
com.example.app.test/androidx.test.runner.AndroidJUnitRunner &
wait
Pattern: WRONG vs RIGHT — running a single method
adb shell am instrument -w -r -e class com.example.app.LoginTests:login_succeeds \
com.example.app.test/androidx.test.runner.AndroidJUnitRunner
adb shell am instrument -w -r -e class com.example.app.LoginTests#login_succeeds \
com.example.app.test/androidx.test.runner.AndroidJUnitRunner
Mandatory rules
- MUST pass
-w to am instrument for any CI/script invocation so the shell waits for the runner to complete (necessary for stdout parsing). MUST NOT gate on $? — am instrument calls System.exit(0) regardless of test outcome.
- MUST pair
-w with -r for CI consumption — raw output is parseable; the decoded report_key_streamresult form is not.
- MUST use
<class>#<method> (hash separator) for single-method selection. Colons or dots fail silently.
- MUST put the orchestrator as the runner (positional last arg) and the AndroidJUnitRunner as the target via
-e targetInstrumentation — not the other way around.
- MUST NOT rely on
am instrument exit codes when -w is omitted.
- MUST NOT assume
clearPackageData true works without Orchestrator — it is an Orchestrator-only argument.
- PREFERRED: use Test Orchestrator +
clearPackageData true for hermetic test isolation in CI; this maps to Gradle's testOptions.execution = "ANDROIDX_TEST_ORCHESTRATOR".
- PREFERRED: disable animations (
settings put global *_animation_scale 0) before the run, or rely on Gradle's testOptions.animationsDisabled = true.
Verification
References