Introduction
Appium is an open-source, cross-platform testing tool that automates native, hybrid, and web applications on iOS, Android, and Windows platforms. Its power lies in using the same API across multiple platforms, allowing testers to write once and run tests anywhere.
Appium Setup Scripts
Command Line Installation
# Install Appium Server
npm install -g appium
# Install platform-specific drivers
npm install -g appium-uiautomator2-driver # For Android
npm install -g appium-xcuitest-driver # For iOS
npm install -g appium-windows-driver # For Windows
# Install Appium Doctor for environment verification
npm install -g appium-doctor
# Check setup status
appium-doctor --android
appium-doctor --ios
# Start Appium Server
appium --address 127.0.0.1 --port 4723
Connection Scripts
Java Driver Initialization
// Android Driver setup
DesiredCapabilities caps = new DesiredCapabilities();
caps.setCapability("platformName", "Android");
caps.setCapability("automationName", "UiAutomator2");
caps.setCapability("deviceName", "Android Device");
caps.setCapability("app", "/path/to/app.apk");
AndroidDriver driver = new AndroidDriver(
new URL("http://127.0.0.1:4723/wd/hub"), caps);
// iOS Driver setup
DesiredCapabilities caps = new DesiredCapabilities();
caps.setCapability("platformName", "iOS");
caps.setCapability("automationName", "XCUITest");
caps.setCapability("deviceName", "iPhone 13");
caps.setCapability("platformVersion", "15.0");
caps.setCapability("app", "/path/to/app.ipa");
IOSDriver driver = new IOSDriver(
new URL("http://127.0.0.1:4723/wd/hub"), caps);
Python Driver Initialization
# Android Driver setup
from appium import webdriver
from appium.webdriver.common.mobileby import MobileBy
caps = {
"platformName": "Android",
"automationName": "UiAutomator2",
"deviceName": "Android Device",
"app": "/path/to/app.apk"
}
driver = webdriver.Remote("http://localhost:4723/wd/hub", caps)
# iOS Driver setup
caps = {
"platformName": "iOS",
"automationName": "XCUITest",
"deviceName": "iPhone 13",
"platformVersion": "15.0",
"app": "/path/to/app.ipa"
}
driver = webdriver.Remote("http://localhost:4723/wd/hub", caps)
Key Capability Scripts
Common Capabilities
// Basic capabilities
caps.setCapability("platformName", "Android"); // or "iOS"
caps.setCapability("deviceName", "device name");
caps.setCapability("app", "path/to/app"); // .apk or .ipa file
// Browser testing
caps.setCapability("browserName", "Chrome"); // or "Safari" for iOS
// Advanced capabilities
caps.setCapability("noReset", true); // Don't reset app state
caps.setCapability("fullReset", false); // Don't uninstall app
caps.setCapability("newCommandTimeout", 60); // Timeout in seconds
caps.setCapability("autoGrantPermissions", true); // Auto-grant app permissions
Android-Specific Capabilities
// For installed app
caps.setCapability("appPackage", "com.example.app");
caps.setCapability("appActivity", "com.example.app.MainActivity");
// Device selection
caps.setCapability("udid", "emulator-5554"); // Specific device by ID
caps.setCapability("avd", "Pixel_4_API_30"); // Start specific emulator
// Advanced Android options
caps.setCapability("skipUnlock", true); // Skip device unlock
caps.setCapability("unlockType", "pin"); // Unlock method
caps.setCapability("unlockKey", "1234"); // PIN code
caps.setCapability("noSign", true); // Skip app signing
caps.setCapability("systemPort", 8201); // Custom system port
iOS-Specific Capabilities
// iOS simulator/real device
caps.setCapability("udid", "00008020-00157936018B802E"); // Real device UDID
caps.setCapability("xcodeOrgId", "ABCD123456"); // Team ID
caps.setCapability("xcodeSigningId", "iPhone Developer"); // Signing identity
// Advanced iOS options
caps.setCapability("useNewWDA", false); // Reuse WebDriverAgent
caps.setCapability("wdaLocalPort", 8100); // WDA port
caps.setCapability("waitForQuiescence", false); // Don't wait for app idle
caps.setCapability("usePrebuiltWDA", true); // Use prebuilt WDA
caps.setCapability("showXcodeLog", true); // Show Xcode logs
Element Location Scripts
Finding Elements
// Java Locators
// By ID
WebElement element = driver.findElement(By.id("login_button"));
// By Accessibility ID (most stable)
WebElement element = driver.findElement(AppiumBy.accessibilityId("login_button"));
// By XPath (least stable, use as last resort)
WebElement element = driver.findElement(By.xpath("//android.widget.Button[@text='Login']"));
// By ClassName
WebElement element = driver.findElements(By.className("android.widget.EditText"));
// By Android UiAutomator
WebElement element = driver.findElement(AppiumBy.androidUIAutomator(
"new UiSelector().resourceId(\"com.example.app:id/login_button\")"));
// By iOS predicate
WebElement element = driver.findElement(AppiumBy.iOSNsPredicateString("name == 'login_button'"));
// By iOS Class Chain
WebElement element = driver.findElement(AppiumBy.iOSClassChain("**/XCUIElementTypeButton[`name == 'Login'`]"));
# Python Locators
from appium.webdriver.common.mobileby import MobileBy
# By ID
element = driver.find_element(MobileBy.ID, "login_button")
# By Accessibility ID
element = driver.find_element(MobileBy.ACCESSIBILITY_ID, "login_button")
# By XPath
element = driver.find_element(MobileBy.XPATH, "//android.widget.Button[@text='Login']")
# By Class Name
elements = driver.find_elements(MobileBy.CLASS_NAME, "android.widget.EditText")
# By Android UiAutomator
element = driver.find_element(MobileBy.ANDROID_UIAUTOMATOR,
'new UiSelector().resourceId("com.example.app:id/login_button")')
# By iOS predicate
element = driver.find_element(MobileBy.IOS_PREDICATE, "name == 'login_button'")
# By iOS Class Chain
element = driver.find_element(MobileBy.IOS_CLASS_CHAIN, "**/XCUIElementTypeButton[`name == 'Login'`]")
Advanced UiAutomator Selectors (Android)
// Find by text
driver.findElement(AppiumBy.androidUIAutomator(
"new UiSelector().text(\"Exact Text\")"));
// Find by partial text
driver.findElement(AppiumBy.androidUIAutomator(
"new UiSelector().textContains(\"Partial\")"));
// Find by description
driver.findElement(AppiumBy.androidUIAutomator(
"new UiSelector().description(\"Content Description\")"));
// Find by resource ID
driver.findElement(AppiumBy.androidUIAutomator(
"new UiSelector().resourceId(\"com.example.app:id/element_id\")"));
// Find clickable elements
driver.findElements(AppiumBy.androidUIAutomator(
"new UiSelector().clickable(true)"));
// Find element based on UiScrollable
driver.findElement(AppiumBy.androidUIAutomator(
"new UiScrollable(new UiSelector().scrollable(true))" +
".scrollIntoView(new UiSelector().text(\"Text to scroll to\"))"));
Advanced iOS Predicate Selectors
// Match exact name
driver.findElement(AppiumBy.iOSNsPredicateString("name == 'Login'"));
// Match partial name
driver.findElement(AppiumBy.iOSNsPredicateString("name CONTAINS 'Log'"));
// Case insensitive match
driver.findElement(AppiumBy.iOSNsPredicateString("name CONTAINS[c] 'login'"));
// Complex predicate with AND/OR
driver.findElement(AppiumBy.iOSNsPredicateString(
"type == 'XCUIElementTypeButton' AND (name CONTAINS 'Login' OR label CONTAINS 'Login')"));
// Match by value
driver.findElement(AppiumBy.iOSNsPredicateString("value == '12345'"));
// Match by enabled status
driver.findElement(AppiumBy.iOSNsPredicateString("enabled == true"));
// Match by element type
driver.findElement(AppiumBy.iOSNsPredicateString("type == 'XCUIElementTypeTextField'"));
Interaction Scripts
Basic Interactions
// Java
// Click on element
element.click();
// Type text
element.sendKeys("text to type");
// Clear field
element.clear();
// Get text
String text = element.getText();
// Get attribute
String value = element.getAttribute("content-desc"); // Android
String value = element.getAttribute("value"); // iOS
// Check if element is displayed
boolean isDisplayed = element.isDisplayed();
// Check if element is enabled
boolean isEnabled = element.isEnabled();
# Python
# Click on element
element.click()
# Type text
element.send_keys("text to type")
# Clear field
element.clear()
# Get text
text = element.text
# Get attribute
value = element.get_attribute("content-desc") # Android
value = element.get_attribute("value") # iOS
# Check if element is displayed
is_displayed = element.is_displayed()
# Check if element is enabled
is_enabled = element.is_enabled()
Advanced Gestures – Java TouchAction
// Import
import io.appium.java_client.TouchAction;
import io.appium.java_client.touch.WaitOptions;
import io.appium.java_client.touch.offset.PointOption;
import java.time.Duration;
// Tap
new TouchAction<>(driver)
.tap(PointOption.point(100, 200))
.perform();
// Long press
new TouchAction<>(driver)
.longPress(PointOption.point(100, 200))
.waitAction(WaitOptions.waitOptions(Duration.ofMillis(2000)))
.release()
.perform();
// Swipe
new TouchAction<>(driver)
.press(PointOption.point(500, 1000))
.waitAction(WaitOptions.waitOptions(Duration.ofMillis(800)))
.moveTo(PointOption.point(500, 200))
.release()
.perform();
// Drag and drop
new TouchAction<>(driver)
.press(PointOption.point(sourceX, sourceY))
.waitAction(WaitOptions.waitOptions(Duration.ofMillis(800)))
.moveTo(PointOption.point(targetX, targetY))
.release()
.perform();
Modern Gesture Controls (W3C Actions API)
// Import
import org.openqa.selenium.interactions.Pause;
import org.openqa.selenium.interactions.PointerInput;
import org.openqa.selenium.interactions.Sequence;
import java.time.Duration;
import java.util.Arrays;
// Create pointer input
PointerInput finger = new PointerInput(PointerInput.Kind.TOUCH, "finger");
// Tap gesture
Sequence tap = new Sequence(finger, 1)
.addAction(finger.createPointerMove(Duration.ZERO, PointerInput.Origin.viewport(), x, y))
.addAction(finger.createPointerDown(PointerInput.MouseButton.LEFT.asArg()))
.addAction(new Pause(finger, Duration.ofMillis(200)))
.addAction(finger.createPointerUp(PointerInput.MouseButton.LEFT.asArg()));
driver.perform(Arrays.asList(tap));
// Swipe gesture
Sequence swipe = new Sequence(finger, 1)
.addAction(finger.createPointerMove(Duration.ZERO, PointerInput.Origin.viewport(), startX, startY))
.addAction(finger.createPointerDown(PointerInput.MouseButton.LEFT.asArg()))
.addAction(new Pause(finger, Duration.ofMillis(200)))
.addAction(finger.createPointerMove(Duration.ofMillis(1000), PointerInput.Origin.viewport(), endX, endY))
.addAction(finger.createPointerUp(PointerInput.MouseButton.LEFT.asArg()));
driver.perform(Arrays.asList(swipe));
Python Gesture Scripts
# Import
from appium.webdriver.common.touch_action import TouchAction
# Tap
TouchAction(driver).tap(x=100, y=200).perform()
# Long press
TouchAction(driver).long_press(x=100, y=200, duration=2000).release().perform()
# Swipe (top to bottom)
TouchAction(driver).press(x=500, y=200).wait(800).move_to(x=500, y=1000).release().perform()
# Swipe (bottom to top)
TouchAction(driver).press(x=500, y=1000).wait(800).move_to(x=500, y=200).release().perform()
# Drag and drop
TouchAction(driver).press(x=source_x, y=source_y).wait(800).move_to(x=target_x, y=target_y).release().perform()
Wait Scripts
Implicit Wait
// Java
driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));
# Python
driver.implicitly_wait(10)
Explicit Wait
// Java
import org.openqa.selenium.support.ui.WebDriverWait;
import org.openqa.selenium.support.ui.ExpectedConditions;
import java.time.Duration;
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
// Wait for element to be visible
WebElement element = wait.until(
ExpectedConditions.visibilityOfElementLocated(By.id("element_id")));
// Wait for element to be clickable
WebElement element = wait.until(
ExpectedConditions.elementToBeClickable(By.id("element_id")));
// Wait for element to be present
WebElement element = wait.until(
ExpectedConditions.presenceOfElementLocated(By.id("element_id")));
// Wait for text to be present in element
boolean isPresent = wait.until(
ExpectedConditions.textToBePresentInElementLocated(By.id("element_id"), "Expected Text"));
# Python
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from appium.webdriver.common.mobileby import MobileBy
wait = WebDriverWait(driver, 10)
# Wait for element to be visible
element = wait.until(EC.visibility_of_element_located((MobileBy.ID, "element_id")))
# Wait for element to be clickable
element = wait.until(EC.element_to_be_clickable((MobileBy.ID, "element_id")))
# Wait for element to be present
element = wait.until(EC.presence_of_element_located((MobileBy.ID, "element_id")))
# Wait for text to be present in element
is_present = wait.until(EC.text_to_be_present_in_element((MobileBy.ID, "element_id"), "Expected Text"))
Custom Wait Functions
// Java
// Wait for element to contain specific text
WebElement element = wait.until(driver -> {
WebElement el = driver.findElement(By.id("element_id"));
return el.getText().contains("Expected Text") ? el : null;
});
// Wait for app to be in specific state
boolean isInState = wait.until(driver -> {
try {
return driver.findElement(By.id("state_indicator")).isDisplayed();
} catch (Exception e) {
return false;
}
});
# Python
# Wait for element to contain specific text
def text_to_be_in_element(locator, text):
def check(driver):
try:
element = driver.find_element(*locator)
return text in element.text
except:
return False
return check
element = wait.until(text_to_be_in_element((MobileBy.ID, "element_id"), "Expected Text"))
# Wait for element to disappear
def element_disappeared(locator):
def check(driver):
try:
driver.find_element(*locator)
return False
except:
return True
return check
wait.until(element_disappeared((MobileBy.ID, "loading_indicator")))
App Management Scripts
App Control
// Java
// Install app
driver.installApp("/path/to/app.apk");
// Check if app is installed
boolean isInstalled = driver.isAppInstalled("com.example.app");
// Launch app
driver.launchApp();
// Close app (without ending session)
driver.closeApp();
// Reset app (clear data)
driver.resetApp();
// Remove app
driver.removeApp("com.example.app");
// Run app in background
driver.runAppInBackground(Duration.ofSeconds(5));
// Activate app (bring to foreground)
driver.activateApp("com.example.app");
// Terminate app (force stop)
driver.terminateApp("com.example.app");
# Python
# Install app
driver.install_app('/path/to/app.apk')
# Check if app is installed
is_installed = driver.is_app_installed('com.example.app')
# Launch app
driver.launch_app()
# Close app (without ending session)
driver.close_app()
# Reset app (clear data)
driver.reset()
# Remove app
driver.remove_app('com.example.app')
# Run app in background
driver.background_app(5)
# Activate app (bring to foreground)
driver.activate_app('com.example.app')
# Terminate app (force stop)
driver.terminate_app('com.example.app')
Device Management Scripts
Device Controls
// Java
// Get device orientation
ScreenOrientation orientation = driver.getOrientation();
// Set device orientation
driver.rotate(ScreenOrientation.LANDSCAPE);
// Lock device
driver.lockDevice();
// Unlock device
driver.unlockDevice();
// Is device locked
boolean isLocked = driver.isDeviceLocked();
// Toggle airplane mode (Android)
((AndroidDriver) driver).toggleAirplaneMode();
// Toggle WiFi (Android)
((AndroidDriver) driver).toggleWifi();
// Toggle location services (Android)
((AndroidDriver) driver).toggleLocationServices();
// Press key code (Android)
((AndroidDriver) driver).pressKey(new KeyEvent(AndroidKey.BACK));
((AndroidDriver) driver).pressKey(new KeyEvent(AndroidKey.HOME));
// Hide keyboard
driver.hideKeyboard();
// Screenshot
File screenshot = driver.getScreenshotAs(OutputType.FILE);
# Python
# Get device orientation
orientation = driver.orientation
# Set device orientation
driver.orientation = "LANDSCAPE"
# Lock device
driver.lock()
# Unlock device
driver.unlock()
# Is device locked
is_locked = driver.is_locked()
# Toggle airplane mode (Android)
driver.toggle_airplane_mode()
# Toggle WiFi (Android)
driver.toggle_wifi()
# Toggle location services (Android)
driver.toggle_location_services()
# Press key code (Android)
from appium.webdriver.extensions.android.nativekey import AndroidKey
driver.press_keycode(AndroidKey.BACK)
driver.press_keycode(AndroidKey.HOME)
# Hide keyboard
driver.hide_keyboard()
# Screenshot
driver.get_screenshot_as_file('screenshot.png')
Hybrid App Scripts
Context Switching
// Java
// Get all contexts
Set<String> contexts = driver.getContextHandles();
for (String context : contexts) {
System.out.println(context); // Typically NATIVE_APP, WEBVIEW_[package_name]
}
// Get current context
String currentContext = driver.getContext();
// Switch to WebView
driver.context("WEBVIEW_com.example.app");
// Switch back to native
driver.context("NATIVE_APP");
// Web context element handling
driver.context("WEBVIEW_com.example.app");
driver.findElement(By.cssSelector("#login-button")).click();
# Python
# Get all contexts
contexts = driver.contexts
for context in contexts:
print(context) # Typically NATIVE_APP, WEBVIEW_[package_name]
# Get current context
current_context = driver.context
# Switch to WebView
driver.switch_to.context('WEBVIEW_com.example.app')
# Switch back to native
driver.switch_to.context('NATIVE_APP')
# Web context element handling
driver.switch_to.context('WEBVIEW_com.example.app')
driver.find_element_by_css_selector('#login-button').click()
Session Management Scripts
Driver Session
// Java
// Create session
DesiredCapabilities caps = new DesiredCapabilities();
// Set capabilities...
AndroidDriver driver = new AndroidDriver(new URL("http://127.0.0.1:4723/wd/hub"), caps);
// Get session ID
String sessionId = driver.getSessionId().toString();
// Get session capabilities
Map<String, Object> caps = driver.getSessionDetails();
// Set timeouts
driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));
// End session
driver.quit();
# Python
# Create session
caps = {}
# Set capabilities...
driver = webdriver.Remote("http://localhost:4723/wd/hub", caps)
# Get session ID
session_id = driver.session_id
# Get session capabilities
caps = driver.capabilities
# Set timeouts
driver.implicitly_wait(10)
# End session
driver.quit()
TestNG Framework Scripts
Basic Test Class
import io.appium.java_client.AppiumDriver;
import io.appium.java_client.android.AndroidDriver;
import org.openqa.selenium.By;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.testng.Assert;
import org.testng.annotations.*;
import java.net.URL;
import java.time.Duration;
public class LoginTest {
private AppiumDriver driver;
@BeforeClass
public void setUp() throws Exception {
DesiredCapabilities caps = new DesiredCapabilities();
caps.setCapability("platformName", "Android");
caps.setCapability("deviceName", "Android Device");
caps.setCapability("app", "/path/to/app.apk");
driver = new AndroidDriver(new URL("http://127.0.0.1:4723/wd/hub"), caps);
driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));
}
@Test
public void testValidLogin() {
driver.findElement(By.id("username")).sendKeys("validUser");
driver.findElement(By.id("password")).sendKeys("validPass");
driver.findElement(By.id("loginButton")).click();
// Verify login success
boolean dashboardDisplayed = driver.findElement(By.id("dashboard")).isDisplayed();
Assert.assertTrue(dashboardDisplayed, "Dashboard should be displayed after login");
}
@Test
public void testInvalidLogin() {
driver.findElement(By.id("username")).sendKeys("invalidUser");
driver.findElement(By.id("password")).sendKeys("invalidPass");
driver.findElement(By.id("loginButton")).click();
// Verify error message
String errorMsg = driver.findElement(By.id("errorMessage")).getText();
Assert.assertEquals(errorMsg, "Invalid credentials", "Error message should be displayed");
}
@AfterClass
public void tearDown() {
if (driver != null) {
driver.quit();
}
}
}
Data-Driven Testing with TestNG
import io.appium.java_client.AppiumDriver;
import io.appium.java_client.android.AndroidDriver;
import org.openqa.selenium.By;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.testng.Assert;
import org.testng.annotations.*;
import java.net.URL;
public class DataDrivenLoginTest {
private AppiumDriver driver;
@BeforeClass
public void setUp() throws Exception {
DesiredCapabilities caps = new DesiredCapabilities();
// Set capabilities...
driver = new AndroidDriver(new URL("http://127.0.0.1:4723/wd/hub"), caps);
}
@DataProvider(name = "loginData")
public Object[][] getLoginData() {
return new Object[][] {
{"validUser", "validPass", true, ""},
{"invalidUser", "invalidPass", false, "Invalid credentials"},
{"", "", false, "Username and password are required"}
};
}
@Test(dataProvider = "loginData")
public void testLogin(String username, String password, boolean shouldPass, String expectedError) {
// Clear fields
driver.findElement(By.id("username")).clear();
driver.findElement(By.id("password")).clear();
// Enter credentials
driver.findElement(By.id("username")).sendKeys(username);
driver.findElement(By.id("password")).sendKeys(password);
driver.findElement(By.id("loginButton")).click();
if (shouldPass) {
// Verify login success
boolean dashboardDisplayed = driver.findElement(By.id("dashboard")).isDisplayed();
Assert.assertTrue(dashboardDisplayed, "Dashboard should be displayed after login");
} else {
// Verify error message
String errorMsg = driver.findElement(By.id("errorMessage")).getText();
Assert.assertEquals(errorMsg, expectedError, "Incorrect error message");
}
}
@AfterClass
public void tearDown() {
if (driver != null) {
driver.quit();
}
}
}
Common Utility Scripts
Screen Action Utilities
// Java
public class ScreenActions {
private AppiumDriver driver;
private WebDriverWait wait;
public ScreenActions(AppiumDriver driver) {
this.driver = driver;
this.wait = new WebDriverWait(driver, Duration.ofSeconds(10));
}
// Scroll down until element is visible
public void scrollToElement(By locator) {
int maxSwipes = 5;
int swipeCount = 0;
while (swipeCount < maxSwipes) {
try {
WebElement element = driver.findElement(locator);
if (element.isDisplayed()) {
return;
}
} catch (Exception e) {
// Element not found, continue scrolling
}
// Get screen dimensions
Dimension size = driver.manage().window().getSize();
int startX = size.width / 2;
int startY = (int) (size.height * 0.8);
int endY = (int) (size.height * 0.2);
// Scroll down
new TouchAction<>(driver)
.press(PointOption.point(startX, startY))
.waitAction(WaitOptions.waitOptions(Duration.ofMillis(800)))
.moveTo(PointOption.point(startX, endY))
.release()
.perform();
swipeCount++;
}
throw new NoSuchElementException("Element not found after scrolling: " + locator);
}
// Tap on center of screen
public void tapOnCenter() {
Dimension size = driver.manage().window().getSize();
int centerX = size.width / 2;
int centerY = size.height / 2;
new TouchAction<>(driver)
.tap(PointOption.point(centerX, centerY))
.perform();
}
// Safe click with wait
public void safeClick(By locator) {
wait.until(ExpectedConditions.elementToBeClickable(locator)).click();
}
// Type text with clear
public void typeText(By locator, String text) {
WebElement element = wait.until(ExpectedConditions.visibilityOfElementLocated(locator));
element.clear();
element.sendKeys(text);
}
// Wait for loading to complete
public void waitForLoadingToComplete(By loadingIndicator) {
try {
wait.until(ExpectedConditions.visibilityOfElementLocated(loadingIndicator));
wait.until(ExpectedConditions.invisibilityOfElementLocated(loadingIndicator));
} catch (Exception e) {
// Loading indicator might not appear if loading is fast
}
}
}
Screenshot Utility
// Java
public class ScreenshotUtils {
private AppiumDriver driver;
private String screenshotDir;
public ScreenshotUtils(AppiumDriver driver, String screenshotDir) {
this.driver = driver;
this.screenshotDir = screenshotDir;
// Create directory if it doesn't exist
File directory = new File(screenshotDir);
if (!directory.exists()) {
directory.mkdirs();
}
}
// Take screenshot with timestamp
public String takeScreenshot(String screenshotName) {
try {
String timestamp = new SimpleDateFormat("yyyyMMdd-HHmmss").format(new Date());
String fileName = screenshotName + "_" + timestamp + ".png";
String filePath = screenshotDir + File.separator + fileName;
File screenshot = driver.getScreenshotAs(OutputType.FILE);
FileUtils.copyFile(screenshot, new File(filePath));
return filePath;
} catch (Exception e) {
System.err.println("Failed to take screenshot: " + e.getMessage());
return null;
}
}
// Take screenshot on test failure
public String takeFailureScreenshot(String testName) {
return takeScreenshot("FAIL_" + testName);
}
}
Expert Performance Optimization Tips
Use fast locator strategies:
- Accessibility ID and ID are significantly faster than XPath
- Use UiAutomator selectors for Android and predicates for iOS for complex queries
Minimize app resets:
// Avoid full reset for every test caps.setCapability("noReset", true); caps.setCapability("fullReset", false);Reuse driver sessions:
- Create one driver session for multiple tests rather than recreating
- Only reset app state between tests rather than reinstalling
Parallel execution:
- Run tests on multiple devices by setting up device farms
- Use TestNG parallel execution with customized port allocation:
// Dynamically assign ports to avoid conflicts caps.setCapability("systemPort", 8200 + threadId);Use explicit waits intelligently:
- Avoid thread.sleep()
- Use shorter implicit waits (2-5 seconds)
- Use explicit waits for specific conditions
Reuse element references:
// Instead of finding the same element multiple times WebElement loginButton = driver.findElement(By.id("loginButton")); if (loginButton.isDisplayed()) { loginButton.click(); }Batch commands when possible:
// Instead of multiple separate finds List<WebElement> formFields = driver.findElements(By.className("android.widget.EditText")); formFields.get(0).sendKeys("username"); formFields.get(1).sendKeys("password");
Resources for Further Learning
Official Documentation
Online Communities
Books
- “Appium Essentials” by Manoj Hans
- “Mastering Mobile Test Automation” by Ruchika Sharma
