算法艺术创作
algorithmic-art
通过代码和可调参数创作生成艺术与交互式视觉效果。
qa-testing-android【设计与创意】Designs Android testing with Espresso, UI Automator, Robolectric, and Compose. Use when planning device matrices, emulator CI, Compose test migration, screenshots, or flakes.
独立 GitHub 快照 · 自动分类 · 以原作者文档为准
Android testing automation with Espresso, UI Automator, Compose Testing, screenshot tests, and adaptive UI validation.
Core References: Android Testing Docs, Build-Managed Devices, Compose Testing, UI Automator, Screenshot Testing, Accessibility Checking
| Task | Command |
|---|---|
| List emulators | emulator -list-avds |
| Start emulator | emulator @<avd_name> |
| List devices | adb devices |
| Install APK | adb install -r <path-to-apk> |
| Run unit tests | ./gradlew test |
| Run instrumented tests (connected) | ./gradlew connectedAndroidTest |
| Run instrumented tests (GMD) | ./gradlew <device><variant>AndroidTest |
| Run screenshot tests | ./gradlew validateDebugScreenshotTest |
| List GMD tasks | `./gradlew tasks --all |
| Clear app data | adb shell pm clear <applicationId> |
Look up current versions before pinning; this table keeps only the compatibility rules.
| Component | Where to check the current version | Stable notes |
|---|---|---|
| Android / API level | Android developer release notes | The newest OS version is not automatically the target-API requirement; see "Google Play Target API Policy" below |
| AGP | https://developer.android.com/build/releases/about-agp | Select the wrapper/JDK from the compatibility table for the installed AGP minor; major-version matching alone is insufficient |
| Robolectric | https://github.com/robolectric/robolectric/releases | Robolectric 4.17 added SDK 37 support. JDK 21 is required for SDK 36+ |
| UI Automator | https://developer.android.com/jetpack/androidx/releases/test-uiautomator | The 2.4 API boundary adds the uiAutomator {} DSL; select the project-approved release |
| Compose Preview Screenshot Testing | Android Studio / AGP release notes | Check plugin vs AGP test-suite setup and CLI vs IDE requirements separately; see screenshot-testing.md |
| ATD images | Emulator system-image list | Check supported API images in the managed-device guide and SDK Manager; ATD disables hardware rendering |
| Maestro | Maestro release notes | New API-level support can reach the local CLI before Maestro Cloud; check before targeting a new Android version |
Before choosing the release matrix, read the target-API requirements
for the app's form factor, submission type, deadline and extension status. New submissions and
existing-app availability have different rules; private apps and Wear/TV/Automotive/XR can have
exceptions. Record the applicable requirement and verify the app's targetSdk in the built artifact.
connectedAndroidTest for local ad-hoc runs.clearPackageData for instrumented suites that need strong isolation.@Preview coverage, Paparazzi or Roborazzi for JVM rendering, device-based snapshots only when hardware fidelity matters.Recommended Gradle defaults for stable instrumented tests:
android {
testOptions {
animationsDisabled = true
execution = "ANDROIDX_TEST_ORCHESTRATOR"
emulatorSnapshots {
enableForTestFailures = true
maxSnapshotsForTestFailures = 2
}
}
}
dependencies {
androidTestUtil(libs.androidx.test.orchestrator)
}
If you rely on test isolation between instrumented tests, also set runner args such as clearPackageData=true in your Gradle or CI wiring.
| Layer | Framework | Scope |
|---|---|---|
| Unit | JUnit + Mockito | JVM, no Android |
| Unit (Android) | Robolectric | JVM, simulated framework |
| UI (Views) | Espresso | Instrumented |
| UI (Compose) | Compose Testing | Instrumented; JVM with explicit Robolectric setup |
| Adaptive UI | Espresso Device API + DeviceConfigurationOverride | Instrumented or host-assisted |
| Screenshot | Compose Preview Screenshot Testing, Paparazzi, Roborazzi | JVM or instrumented |
| System | UI Automator | Cross-app, system UI, benchmarking drivers |
testOptions { animationsDisabled = true } for instrumented tests.waitUntil, or UI Automator conditions instead of sleeps.MockWebServer or DI fakes; avoid live backends in CI.withId() for Views, testTag for Compose, and resource-id or content descriptions for UI Automator.A checklist says "use emulators for CI, real devices for release." The judgment call is which real-device signals are worth paying for:
Generic "flaky test" triage wastes time re-running instead of classifying. Android UI-test flakiness clusters into a small number of root-cause families — identify which one you're looking at before reaching for retries:
NoMatchingViewException or an assertion firing against a stale loading state. Root cause is almost always an unregistered IdlingResource (Espresso) or a missing waitUntil/synchronized TestDispatcher (Compose/coroutines) — see references/espresso-patterns.md for the registration trap.testOptions { animationsDisabled = true } for CI. Only fall back to the per-test adb-settings DisableAnimationsRule pattern in references/espresso-patterns.md when the Gradle flag is unavailable (for example, a local module or Gradle version that predates it) — label it "legacy" in your own suite, since the two mechanisms can silently disagree if both are present.testTag inside a Material component (e.g. the Text inside a Button) is invisible to onNodeWithTag because merged descendants collapse into the parent node; or a multi-value assertion like assertTextEquals("Save") fails against a merged node's full Text list. Text finders such as onNodeWithText still match the merged parent by default — this is not a "finds nothing" bug, and not a timing issue at all; do not "fix" it with a wait loop. See the corrected merged-tree trap in references/compose-testing.md. A v1-to-v2 migration can instead expose queued coroutine work; classify that under synchronization gaps (#1), using the migration section in references/compose-testing.md.clearPackageData, not by reordering tests.System.currentTimeMillis(), or unseeded random data leaking into assertions or screenshot goldens. Always mockable; the fact that it's still happening usually means a fake wasn't reused when a new screen was added.When a test is flaky, name which of the seven it is before touching the test — the fix for #1 (register/await) will not touch #4 (isolate/clear state), and applying #2's fix (disable animations) to a #5 issue (Doze) does nothing.
The classic pyramid (many unit tests, some integration, few E2E) still holds, but Compose changes where the middle layer sits:
createComposeRule() still hosts your content in a ComponentActivity under the hood and runs instrumented on a device or emulator unless the module also runs it under Robolectric in test/ — it is not automatically device-free. What it does avoid is your app's own Activity, DI graph, and navigation. Prefer it over createAndroidComposeRule<Activity>() whenever the composable doesn't need real navigation, DI graph, or activity lifecycle, and run it under Robolectric (Roborazzi or a @RunWith(AndroidJUnit4) + isIncludeAndroidResources JVM test) when you actually want a fast, unit-test-like run. See references/compose-testing.md for the setup.StateFlow, not through the UI). A Compose app that only has "instrumented Compose tests that also exercise the ViewModel" has recreated the old inverted pyramid with new tools.Screenshot testing has real setup and maintenance cost (goldens go stale, false positives from font/renderer drift, review burden on every intentional UI change). It is worth that cost when:
It is a poor early investment for a small team still iterating rapidly on visual design — churn in intentional goldens will dominate signal from real regressions. Start with host-side tools (Compose Preview Screenshot Testing, Paparazzi, Roborazzi) for cheap iteration; only add device-based snapshot testing (Shot, or ATD-excluded device runs) once a specific rendering-sensitive surface (WebView, Maps, camera preview, custom Canvas/GPU work) has already caused a shipped visual bug that host-side rendering could not have caught.
references/espresso-patterns.mdreferences/compose-testing.mdreferences/uiautomator.mdreferences/screenshot-testing.mdreferences/adaptive-screen-testing.mdreferences/accessibility-checks.mdThe v1 Compose test APIs (androidx.compose.ui.test.junit4.createComposeRule) are deprecated. v2
(...junit4.v2.createComposeRule, ...test.v2.runComposeUiTest, from ui-test-junit4
1.11.0-alpha03+) switches the default dispatcher from UnconfinedTestDispatcher to
StandardTestDispatcher and forces touch input mode by default. Standard UI assertions already synchronize; direct state reads and manual clock control can need
waitForIdle()/runOnIdle {} or scheduler advancement (taxonomy item #1). See references/compose-testing.md for the full migration guide,
failure-class breakdown, and code samples.
id, Compose Modifier.testTag, system resource-id or content description.Thread.sleep().connectedAndroidTest or a single managed-device task before widening the matrix.@Preview-driven Compose UI states.waitUntil, onElement, or watcher-based synchronization.build/reports/androidTests/, screenshot reports, diff images, logcat, and managed-device outputs.# Screenshot
adb exec-out screencap -p > screenshot.png
# Screen recording
adb shell screenrecord /sdcard/demo.mp4
# Pull managed-device test artifacts after a local failure
adb pull /sdcard/Android/media ./device-artifacts
Preferred: build-managed devices. See references/gradle-managed-devices.md and references/android-ci-optimization.md.
# .github/workflows/android.yml
name: Android CI
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6 # or later — verify at actions/checkout releases
- uses: actions/setup-java@v5 # or later
with:
java-version: '21' # SDK 36 unit tests need JDK 21
distribution: 'temurin'
- uses: gradle/actions/setup-gradle@v5 # or later
- run: ./gradlew testDebugUnitTest <device><api>DebugAndroidTest -Pandroid.testoptions.manageddevices.emulator.gpu=swiftshader_indirect
The reference guides are intentionally large; search within them instead of loading everything:
rg -n "^## " skills/universal/qa-testing-android/references/compose-testing.mdrg -n "Idling|waitUntil|Synchronization" skills/universal/qa-testing-android/references/compose-testing.mdrg -n "DisplaySizeRule|DeviceConfigurationOverride|fold" skills/universal/qa-testing-android/references/adaptive-screen-testing.mdrg -n "PreviewTest|Paparazzi|Roborazzi|Shot" skills/universal/qa-testing-android/references/screenshot-testing.mdMainDispatcherRule + TestDispatcher (runTest { }, advanceUntilIdle(), kotlinx-coroutines-test) for every ViewModel and StateFlow test — choose eager UnconfinedTestDispatcher only when that scheduling behavior is intentional, because it can mask ordering races@Serializable endpoint per data class, so R8 full-mode stripping of kotlinx-serialization $serializer classes is caught before release (see software-android-runtime-debugging/references/proguard-r8-triage.md)onNodeWithTag(...).assertTextEquals(...) — not on reference equality of UI state objects, because Strong Skipping Mode means the UI may or may not receive the same instance across emissionsThread.sleep() for synchronizationStateFlow<UiState> reference equality across emissions (assertThat(state).isSameInstanceAs(previous)) — new data class instances from copy() have different references but structurally equal content; test semantic equality, not identity| Resource | Purpose |
|---|---|
| references/espresso-patterns.md | Espresso matchers and actions |
| references/compose-testing.md | Compose testing guide |
| references/uiautomator.md | UI Automator patterns for system UI and benchmarking |
| references/gradle-managed-devices.md | Managed device setup and CI |
| references/screenshot-testing.md | Visual regression testing |
| references/adaptive-screen-testing.md | Screen-size and foldable coverage |
| references/accessibility-checks.md | Accessibility checks for Espresso and Compose |
| references/test-orchestrator-patterns.md | AndroidX Test Orchestrator patterns |
| references/android-ci-optimization.md | CI pipeline optimization |
| references/modern-test-tooling.md | JUnit 5, MockK, Turbine, Robolectric, Maestro |
| data/sources.json | Curated external sources |
| Template | Purpose |
|---|---|
| assets/template-android-test-checklist.md | Stability checklist |
| Skill | Purpose |
|---|---|
| software-mobile | Android development |
| qa-testing-strategy | Test strategy |
| qa-testing-mobile | Cross-platform mobile |
| software-android-native | Native Android implementation and agent workflows |
| software-android-runtime-debugging | Build/install/launch proof and stale-build triage |
| software-android-design | Native Android visual design and Material 3 review |
When prior decisions or pitfalls are relevant, consult learnings.consolidated.md if present; use learnings.md only for needed history or as the available fallback. Otherwise skip both.
After applying it, if you encountered a pattern worth remembering, a mistake worth preventing, or a domain fact that surprised you, append one dated bullet to learnings.md via agents-skills-feedback-loop/scripts/append_learning.py. Do not modify SKILL.md itself.