Gradle Plugin
We maintain a Gradle plugin that uploads your Android app to TestingBot Storage and runs Espresso tests on TestingBot's real device cloud, straight from your build, with no curl scripts required.
-
testingbotUploaduploads an APK to TestingBot Storage and returns a reusabletb://<appkey>identifier. -
testingbotEspressouploads your app and instrumented test APK, runs Espresso across one or more devices, waits for the results, downloads a JUnit XML report, and fails the build on test failures. -
testingbotDeviceslists the Android devices available on your account. - Reads credentials from the DSL, Gradle properties or environment variables, and is configuration-cache compatible with no extra HTTP dependencies on your build classpath.
The plugin is published on the Gradle Plugin Portal and the source is available on GitHub.
Requirements
- Gradle 8.0 or newer, running on JDK 17 or newer.
- A TestingBot account. Grab your key and secret from the member area.
1. Installation
Apply the plugin in your Android app module's build file.
// build.gradle.kts
plugins {
id("com.testingbot.gradle") version "0.1.0"
}
Using the Groovy DSL:
// build.gradle
plugins {
id 'com.testingbot.gradle' version '0.1.0'
}
2. Credentials
Credentials are resolved in this order, first match wins:
- The DSL:
testingbot { key.set("…"); secret.set("…") } - Gradle properties:
-Ptestingbot.key=… -Ptestingbot.secret=…(or ingradle.properties) - Environment variables:
TESTINGBOT_KEY/TESTINGBOT_SECRET
In CI, prefer environment variables backed by secrets. Never commit credentials to your repository.
3. Usage
Configure the testingbot { } block with your APKs and the device capabilities you want to run on.
testingbot {
// Credentials (optional here if provided via env vars / gradle properties)
key.set(providers.environmentVariable("TESTINGBOT_KEY"))
secret.set(providers.environmentVariable("TESTINGBOT_SECRET"))
// The app + instrumented test APKs
appApk.set(layout.projectDirectory.file("app/build/outputs/apk/debug/app-debug.apk"))
testApk.set(
layout.projectDirectory.file("app/build/outputs/apk/androidTest/debug/app-debug-androidTest.apk")
)
// One run is started per capability. Keys are passed through to TestingBot verbatim.
capabilities.set(
listOf(
mapOf("deviceName" to "Pixel.*", "version" to "14", "platformName" to "Android", "realDevice" to true),
mapOf("deviceName" to "Galaxy S.*", "version" to "13", "platformName" to "Android")
)
)
// Optional behavior
waitForResults.set(true) // poll until the run completes (default true)
failBuildOnTestFailure.set(true) // default true
reportXml.set(layout.buildDirectory.file("testingbot/espresso-junit.xml"))
}
deviceName accepts a regular expression, so "Pixel.*" matches any Pixel and "*" matches any device. Commonly used keys are deviceName, version, platformName ("Android"), realDevice, phoneOnly and tabletOnly. Run ./gradlew testingbotDevices to see what is available on your plan.
4. Tasks
# Upload only
./gradlew testingbotUpload
# Build the APKs first, then run Espresso on TestingBot
./gradlew assembleDebug assembleDebugAndroidTest testingbotEspresso
# Discover device names/versions for your capabilities
./gradlew testingbotDevices
5. Android Gradle Plugin auto-wiring
If the com.android.application plugin is applied, naming a variant lets the plugin fill in the conventional APK paths and depend on the matching assemble tasks automatically.
testingbot {
autoWireFromVariant.set("debug") // defaults appApk/testApk + dependsOn assembleDebug(AndroidTest)
capabilities.set(listOf(mapOf("deviceName" to "Pixel.*", "version" to "14", "platformName" to "Android")))
}
Now ./gradlew testingbotEspresso builds the APKs and runs the tests in one go. Explicitly set appApk / testApk paths always take precedence.
Full DSL reference
| Property | Type | Default | Description |
|---|---|---|---|
key |
String |
TESTINGBOT_KEY / testingbot.key
|
API key |
secret |
String |
TESTINGBOT_SECRET / testingbot.secret
|
API secret |
apiBaseUrl |
String |
https://api.testingbot.com/v1 |
API base URL |
appApk |
RegularFile |
— | App APK to upload / test |
testApk |
RegularFile |
— | Instrumented Espresso test APK |
capabilities |
List<Map<String, Any>> |
[] |
One run per entry; passed through verbatim |
espressoOptions |
Map<String, Any> |
{} |
Optional run options passed through verbatim |
waitForResults |
Boolean |
true |
Poll until the run completes |
pollIntervalSeconds |
Long |
15 |
Seconds between status polls |
timeoutMinutes |
Long |
30 |
Max minutes to wait for results |
failBuildOnTestFailure |
Boolean |
true |
Fail the build when a run reports failures |
reportXml |
RegularFile |
build/testingbot/espresso-junit.xml |
Where to write the JUnit report |
autoWireFromVariant |
String |
— | Optional AGP variant to auto-wire |
CI example (GitHub Actions)
- uses: actions/setup-java@v4
with: { distribution: temurin, java-version: 21 }
- run: ./gradlew assembleDebug assembleDebugAndroidTest testingbotEspresso
env:
TESTINGBOT_KEY: ${{ secrets.TESTINGBOT_KEY }}
TESTINGBOT_SECRET: ${{ secrets.TESTINGBOT_SECRET }}