agents/skills/android-unit-test/SKILL.md
This skill provides comprehensive guidance on choosing, writing, running, and
migrating Android test cases across Chromium's three major Java test tiers
(chrome_junit_tests, chrome_public_unit_test_apk, and
chrome_public_test_apk).
When writing or refactoring Android Java tests in Chromium, always aim for the lightest, fastest test tier that satisfies the requirements of the code being tested:
| Target Suite | Execution Environment | Best For | Key Constraints & Rules |
|---|---|---|---|
chrome_junit_tests (junit/) | Host JVM via Robolectric (BaseRobolectricTestRunner) | Pure Java utility methods, data structures, MVC/MVC mediators (*MediatorUnitTest.java), presenter logic, string manipulation, and mock-based testing. | Fastest execution. No actual hardware/emulator required. Cannot execute real native NDK code or live browser profiles without shadow structures or stubs. |
chrome_public_unit_test_apk (unit_device_javatests) | Device / Emulator (BaseJUnit4ClassRunner + @Batch(Batch.UNIT_TESTS)) | Unit tests requiring actual Android device features (such as PackageManager checks, real layout inflating/rendering with BlankUiTestActivity, or localized JNI helper methods like CurrencyFormatter). | Configured with is_unit_test = true: any attempts to initialize the main browser process or start ChromeTabbedActivity will explicitly fail. |
chrome_public_test_apk (javatests/) | Device / Emulator Instrumentation (ChromeTabbedActivityTestRule, BaseJUnit4ClassRunner) | Full end-to-end multi-component browser profile initialization, web page interactions (startOnWebPage, embeddedTestServer), and complex UI flows across Activities. | Heaviest and slowest tier. Should be reserved exclusively for full browser activity & integration flows. |
When converting instrumentation tests from chrome_public_test_apk
(javatests/) to host unit tests (chrome_junit_tests / junit/) or on-device
unit tests (chrome_public_unit_test_apk), follow these key rules:
@Batch in chrome_junit_tests: Robolectric host unit tests on the
JVM are naturally batched by default; do NOT add @Batch annotations to
tests under junit/.@UiThreadTest in chrome_junit_tests: Robolectric tests execute on
the main looper thread automatically. Strip
import androidx.test.annotation.UiThreadTest; and method-level
@UiThreadTest annotations completely when converting to
chrome_junit_tests.CurrencyFormatter in PriceUtils.formatPrice) that cannot be
mocked, place it in chrome_public_unit_test_apk (unit_device_javatests)
instead of chrome_junit_tests.chrome_junit_tests)javatests/src/... to junit/src/...
via git mv.@RunWith(BaseJUnit4ClassRunner.class) or
ChromeJUnit4ClassRunner with:
import org.chromium.base.test.BaseRobolectricTestRunner;
@RunWith(BaseRobolectricTestRunner.class)
@Batch(...) and @UiThreadTest.ThreadUtils.runOnUiThreadBlocking(() -> Mockito.mock(...)) with direct
Mockito initialization: Mockito.mock(...).BUILD.gn: Move the test source out of the javatests target
into a robolectric_library("junit") target:
robolectric_library("junit") {
testonly = true
sources = [
"junit/src/org/chromium/chrome/browser/mycomponent/MyComponentUnitTest.java",
]
deps = [
":java",
"//base:base_java_test_support",
"//base:base_junit_test_support",
"//third_party/androidx:androidx_test_runner_java",
"//third_party/junit",
"//third_party/mockito:mockito_java",
]
}
chrome_public_unit_test_apk)@RunWith(BaseJUnit4ClassRunner.class) along
with @Batch(Batch.UNIT_TESTS) or @Batch(Batch.PER_CLASS).BUILD.gn: Define a dedicated unit_device_javatests
target within your component and register it inside
chrome_public_unit_test_apk (//chrome/android/BUILD.gn):
android_library("unit_device_javatests") {
testonly = true
resources_package = "org.chromium.chrome.browser.mycomponent"
sources = [ "javatests/src/org/chromium/chrome/browser/mycomponent/MyComponentDeviceUnitTest.java" ]
deps = [
":java",
"//base:base_java",
"//base:base_java_test_support",
"//third_party/androidx:androidx_test_runner_java",
"//third_party/junit",
]
}
Before running tests locally, always compile the specific target first.
chrome_junit_tests)autoninja -C out/Debug chrome_junit_tests && \
out/Debug/bin/run_chrome_junit_tests -f "*MyComponentUnitTest*"
chrome_public_unit_test_apk)Always specify your emulator or device explicitly with -d:
autoninja -C out/Debug chrome_public_unit_test_apk && \
out/Debug/bin/run_chrome_public_unit_test_apk -f "*MyComponentDeviceUnitTest*" -d emulator-5554