Guides

Appium with Kotlin and JUnit 5

A working Kotlin/JUnit 5 test for an Android build on SpawnDroid, with UiAutomator2 options, AppiumBy selectors and teardown.

The Kotlin path uses the same Appium Java client and UiAutomator2 driver. The test is idiomatic Kotlin: UiAutomator2Options, apply, and JUnit 5 lifecycle methods.

Gradle dependencies

Use the current Appium Java client and JUnit 5 from Maven Central:

build.gradle.kts
dependencies {
    testImplementation("io.appium:java-client:REPLACE_ME")
    testImplementation("org.junit.jupiter:junit-jupiter:REPLACE_ME")
}

tasks.test {
    useJUnitPlatform()
}

The test

src/test/kotlin/CheckoutTest.kt
import io.appium.java_client.AppiumBy
import io.appium.java_client.android.AndroidDriver
import io.appium.java_client.android.options.UiAutomator2Options
import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.Assertions.assertTrue
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import java.net.URL

class CheckoutTest {
  private lateinit var driver: AndroidDriver

  @BeforeEach
  fun setUp() {
    val options = UiAutomator2Options().apply {
      setPlatformName("Android")
      setAutomationName("UiAutomator2")
      setUdid(System.getenv("SPAWNDROID_UDID"))
      setAppPackage(System.getenv("SPAWNDROID_APP_PACKAGE"))
      setAutoGrantPermissions(true)
    }
    driver = AndroidDriver(
      URL(System.getenv("SPAWNDROID_WD_URL")),
      options,
    )
  }

  @Test
  fun addsItemToCart() {
    driver.findElement(AppiumBy.accessibilityId("Add to cart")).click()
    val total = driver.findElement(
      AppiumBy.id("com.acme.checkout:id/total")
    )
    assertTrue(total.isDisplayed, "Cart total should be visible")
  }

  @AfterEach
  fun tearDown() {
    driver.quit()
  }
}

Do not set appium:app. The build is already installed on the session device.

Run it

export SPAWNDROID_WD_URL='https://stream.spawndroid.io/ci/sess_…/token/wd/hub'
export SPAWNDROID_UDID='emulator-5554'
export SPAWNDROID_APP_PACKAGE='com.acme.checkout'
./gradlew test

Gradle writes JUnit XML under build/test-results/test. Pass that path to the GitHub Action's report-path input so failures show on the run page.

Kotlin-specific notes

  • UiAutomator2Options is a typed builder; prefer it to a raw DesiredCapabilities map.
  • AppiumBy.accessibilityId maps to a content description, not a resource id.
  • Use @AfterEach rather than a JVM shutdown hook. The hook may run after the CI step has already timed out, leaving the device reserved.
  • If you assert inside a helper, let the exception propagate; JUnit records the failure and the teardown still runs.

In CI

- uses: kl3jvi/spawndroid/actions/android-test@v1
  with:
    api-key: ${{ secrets.SPAWNDROID_API_KEY }}
    app-path: app/build/outputs/apk/debug/app-debug.apk
    command: ./gradlew test
    report-path: build/test-results/test

Run it on SpawnDroid

Start free with 200 device-minutes a month, or read the capabilities guide.

Was this page helpful?

On this page