--- name: android-test-batching description: >- Guide for auditing and applying batching annotations (@Batch) and AutoReset rules (AutoResetCtaTransitTestRule) to Android javatests in Chromium. Use this skill when optimizing Java instrumentation test runtimes, resolving test state leaks, or migrating tests to batched execution. --- # Android Instrumentation Test Batching Guide This skill provides step-by-step instructions for auditing, batching, and migrating Chromium Android instrumentation tests (`javatests`) to `@Batch(Batch.PER_CLASS)` and `AutoResetCtaTransitTestRule`. ## Core Invariants 1. **`AutoReset` requires `@Batch`**: `AutoResetCtaTransitTestRule` (`ChromeTransitTestRules.fastAutoResetCtaActivityRule()`) is **only useful when `@Batch` annotations are present**. Without `@Batch`, the Android test runner restarts the browser process between test methods anyway, rendering `AutoReset` ineffective. 2. **`@Batch` is useful independently of `AutoReset`**: `@Batch(Batch.PER_CLASS)` avoids test runner restarts across test methods. ### 1. Inspect Existing Annotations & Rules - Check the test class for existing annotations: - If `@DoNotBatch` is present, inspect the documented reason before modifying. - If `@Batch` is already present, check if `FreshCtaTransitTestRule` can be upgraded to `AutoResetCtaTransitTestRule`. ### 2. Adding Annotations & Activity Rules - Add `@Batch(Batch.PER_CLASS)` to the class definition. - Prefer `AutoResetCtaTransitTestRule` over `FreshCtaTransitTestRule` for faster execution: ```java // Change: @Rule public FreshCtaTransitTestRule mActivityTestRule = ChromeTransitTestRules.freshChromeTabbedActivityRule(); // To: @Rule public AutoResetCtaTransitTestRule mActivityTestRule = ChromeTransitTestRules.fastAutoResetCtaActivityRule(); ``` ### 3. API Adaptations & Code Caveats - **`startOnUrl` vs `startOnWebPage`**: `FreshCtaTransitTestRule.startOnUrl(url)` does not exist on `AutoResetCtaTransitTestRule`. Replace calls with `mActivityTestRule.startOnWebPage(mTestServer.getURL(url))` or `mActivityTestRule.startOnWebPage(url)`. - **FreshCta-Specific Methods**: Methods like `skipWindowAndTabStateCleanup()` in `tearDown()` are specific to `FreshCtaTransitTestRule`. Keep `FreshCtaTransitTestRule` if such cleanup overrides are required. ______________________________________________________________________ ## Cleaning Up State Bleed Across Batched Tests State bleed across consecutive test methods in a batch can stem from various sources. Below are common, non-exhaustive examples and cleanup mechanisms to attempt before giving up or resorting to `@DoNotBatch`: ### 1. Finishing Stray Non-ChromeActivity Instances If secondary or settings activities launched during a test method linger into subsequent test runs: ```java ThreadUtils.runOnUiThreadBlocking(() -> { for (Activity activity : ApplicationStatus.getRunningActivities()) { if (!(activity instanceof ChromeTabbedActivity) && !activity.isFinishing()) { activity.finish(); } } }); ``` Or use `ApplicationTestUtils.finishActivity(activity)`. ### 2. Clearing Snackbar Bleed If snackbars shown in one test method leak into subsequent tests: ```java ThreadUtils.runOnUiThreadBlocking(() -> { SnackbarManager snackbarManager = mSnackbarManagerSupplier.get(); if (snackbarManager != null) { snackbarManager.dismissAllSnackbars(); } }); ``` ### 3. Clearing Dialog Bleed If modal dialogs remain open across tests: ```java ThreadUtils.runOnUiThreadBlocking(() -> { ModalDialogManager modalDialogManager = mModalDialogManagerSupplier.get(); if (modalDialogManager != null && modalDialogManager.isShowing()) { modalDialogManager.dismissAllDialogs(DialogDismissalCause.UNKNOWN); } }); ``` ### 4. Adding `ForTesting()` Reset Methods If production components or singletons retain state across test methods, add explicit reset methods to production or test helper classes: ```java // Example in production/helper component: public static void resetForTesting() { sInstance = null; // Clear static observers or registered handlers } // Invoke in test @After or @Before: @After public void tearDown() { MySingletonComponent.resetForTesting(); } ``` ### 5. When to Use `@DoNotBatch` Only annotate with `@DoNotBatch(reason = "")` if process-level state persists that cannot be easily reset via `ForTesting()` methods, cleanup utilities, or test rules. ______________________________________________________________________ ## Test Verification Verify the batched test suite using `autotest.py`: ```bash ./tools/autotest.py -C out/ --avd-config ``` > [!TIP] **Finding AVD Configs**: It is strongly encouraged to pass > `--avd-config` when running non-JUnit Android tests. Available emulator > configurations can be found by inspecting the files in > `tools/android/avd/proto/` (e.g. > `tools/android/avd/proto/android_36_google_apis_x64.textpb`). Ensure all test > methods pass sequentially in a single run without hanging or failing due to > state bleed.