Appium
Set up Appium for mobile testing and integrate test results with TestKase.
Overview
Appium is an open-source mobile automation framework for testing native, hybrid, and mobile web applications on iOS and Android. It follows a client-server architecture — the Appium server speaks the WebDriver protocol, and you write tests in your preferred language using one of the official clients (Java, JavaScript, or Python).
To integrate Appium results with TestKase, use a test runner that generates structured XML output. With
TestNG, use --format testng and point the reporter at the TestNG results file. With JUnit, use
--format junit.
Prerequisites
- Node.js 18+ — required for the Appium server
- Java 11+ or Python 3.8+ — for your test client
- Android SDK (for Android testing) or Xcode (for iOS testing)
- A physical device or emulator/simulator configured and accessible
Installation
Appium Server
Install the Appium server globally via npm:
npm install -g appiumInstall the platform driver you need:
appium driver install uiautomator2 # Android
appium driver install xcuitest # iOSJava Client (Maven)
Add the Appium Java client to your pom.xml:
<dependency>
<groupId>io.appium</groupId>
<artifactId>java-client</artifactId>
<version>9.1.0</version>
</dependency>JavaScript Client
npm install --save-dev webdriverio @wdio/appium-servicePython Client
pip install Appium-Python-ClientProject Setup
The following example uses Java with TestNG. Add both the Appium client and TestNG to your pom.xml:
<!-- pom.xml -->
<dependencies>
<dependency>
<groupId>io.appium</groupId>
<artifactId>java-client</artifactId>
<version>9.1.0</version>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>7.9.0</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.2.5</version>
</plugin>
</plugins>
</build>Create a base test class that configures the desired capabilities for Android:
// src/test/java/com/example/BaseTest.java
package com.example;
import io.appium.java_client.android.AndroidDriver;
import io.appium.java_client.android.options.UiAutomator2Options;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import java.net.MalformedURLException;
import java.net.URL;
public class BaseTest {
protected AndroidDriver driver;
@BeforeMethod
public void setUp() throws MalformedURLException {
UiAutomator2Options options = new UiAutomator2Options()
.setPlatformName("Android")
.setDeviceName("emulator-5554")
.setApp("/path/to/app.apk")
.setAutomationName("UiAutomator2");
driver = new AndroidDriver(new URL("http://127.0.0.1:4723"), options);
}
@AfterMethod
public void tearDown() {
if (driver != null) {
driver.quit();
}
}
}Writing Tests
Create a test class extending the base class:
// src/test/java/com/example/LoginTest.java
package com.example;
import io.appium.java_client.AppiumBy;
import org.openqa.selenium.WebElement;
import org.testng.Assert;
import org.testng.annotations.Test;
public class LoginTest extends BaseTest {
@Test(description = "[48271] testValidLogin")
public void testValidLogin() {
WebElement emailField = driver.findElement(AppiumBy.accessibilityId("emailInput"));
emailField.sendKeys("user@example.com");
WebElement passwordField = driver.findElement(AppiumBy.accessibilityId("passwordInput"));
passwordField.sendKeys("password123");
WebElement loginButton = driver.findElement(AppiumBy.accessibilityId("loginButton"));
loginButton.click();
WebElement dashboard = driver.findElement(AppiumBy.accessibilityId("dashboardTitle"));
Assert.assertTrue(dashboard.isDisplayed(), "Dashboard should be visible after login");
}
@Test(description = "[48272] testInvalidPassword")
public void testInvalidPassword() {
WebElement emailField = driver.findElement(AppiumBy.accessibilityId("emailInput"));
emailField.sendKeys("user@example.com");
WebElement passwordField = driver.findElement(AppiumBy.accessibilityId("passwordInput"));
passwordField.sendKeys("wrong");
WebElement loginButton = driver.findElement(AppiumBy.accessibilityId("loginButton"));
loginButton.click();
WebElement errorMsg = driver.findElement(AppiumBy.accessibilityId("errorMessage"));
Assert.assertEquals(errorMsg.getText(), "Invalid credentials");
}
}Each test includes a 5-digit Automation ID in its @Test(description) annotation using square brackets.
The @testkase/reporter CLI extracts these IDs using the regex \[(\d{5})\]. For the tests above:
48271→ linked to the "valid login" test case in TestKase48272→ linked to the "invalid password" test case in TestKase
Generate Automation IDs in TestKase first, then embed them in your @Test(description) annotations.
The [XXXXX] pattern can appear anywhere in the description string.
Running Tests
Start the Appium server in a separate terminal:
appiumRun the tests with Maven:
mvn testTestNG generates an XML results file at test-output/testng-results.xml by default.
You can customize the TestNG output directory by configuring the maven-surefire-plugin or passing
-DoutputDir=custom-output to your TestNG suite.
TestKase Integration
After tests complete and the TestNG XML is generated, report results to TestKase:
npx @testkase/reporter report \
--token $TESTKASE_PAT \
--project-id PRJ-1 \
--org-id 1173 \
--cycle-id TCYCLE-5 \
--format testng \
--results-file test-output/testng-results.xml--cycle-id is optional. If not provided, results are reported to TCYCLE-1 — the master test cycle for the project.
Automation ID Mapping
The reporter extracts 5-digit Automation IDs from test descriptions using the [XXXXX] bracket pattern:
| Test Code | Extracted ID |
|---|---|
@Test(description = "[48271] testValidLogin") | 48271 |
@Test(description = "[48272] testInvalidPassword") | 48272 |
@Test(description = "[48273] testAddItem") | 48273 |
The [XXXXX] pattern can appear anywhere in the @Test(description) value. Generate the 5-digit ID
in TestKase first, then embed it in your test annotation.
Complete Example
1. Test File
// src/test/java/com/example/LoginTest.java
package com.example;
import io.appium.java_client.AppiumBy;
import org.openqa.selenium.WebElement;
import org.testng.Assert;
import org.testng.annotations.Test;
public class LoginTest extends BaseTest {
@Test(description = "[48271] testValidLogin")
public void testValidLogin() {
WebElement emailField = driver.findElement(AppiumBy.accessibilityId("emailInput"));
emailField.sendKeys("user@example.com");
WebElement passwordField = driver.findElement(AppiumBy.accessibilityId("passwordInput"));
passwordField.sendKeys("password123");
driver.findElement(AppiumBy.accessibilityId("loginButton")).click();
WebElement dashboard = driver.findElement(AppiumBy.accessibilityId("dashboardTitle"));
Assert.assertTrue(dashboard.isDisplayed());
}
@Test(description = "[48272] testInvalidPassword")
public void testInvalidPassword() {
driver.findElement(AppiumBy.accessibilityId("emailInput")).sendKeys("user@example.com");
driver.findElement(AppiumBy.accessibilityId("passwordInput")).sendKeys("wrong");
driver.findElement(AppiumBy.accessibilityId("loginButton")).click();
WebElement errorMsg = driver.findElement(AppiumBy.accessibilityId("errorMessage"));
Assert.assertEquals(errorMsg.getText(), "Invalid credentials");
}
}2. Start Appium and Run Tests
# Terminal 1 — start the Appium server
appium
# Terminal 2 — run the tests
mvn test3. Report Results to TestKase
npx @testkase/reporter report \
--token $TESTKASE_PAT \
--project-id PRJ-1 \
--org-id 1173 \
--cycle-id TCYCLE-5 \
--format testng \
--results-file test-output/testng-results.xmlTroubleshooting
Appium server not starting
Verify that Node.js 18+ is installed (node -v) and that no other process is using port 4723. You can
specify a different port with appium --port 4724. Also ensure the platform driver is installed:
appium driver list --installedIf the driver is missing, install it with appium driver install uiautomator2 (Android) or
appium driver install xcuitest (iOS).
Device not found
For Android, confirm that the emulator is running or the device is connected with USB debugging enabled:
adb devicesFor iOS, ensure the simulator is booted or the physical device is trusted. Check the deviceName and
platformVersion in your desired capabilities match the available device.
Session creation failed
This usually means the desired capabilities are misconfigured. Common causes:
- The
apppath does not point to a valid.apkor.ipafile - The
platformVersiondoes not match the device/emulator OS version - The
automationNameis not set (should beUiAutomator2for Android orXCUITestfor iOS)
Run Appium with verbose logging to get detailed error output:
appium --log-level debug