How to Use Appium with TestNG for Mobile App Testing
Set up Appium and TestNG in Java, create reliable mobile test sessions, and run them on an emulator or real device.
To use Appium with TestNG, let TestNG organize and run Java test methods, and use Appium’s Java client to control a mobile app through an Appium server and the driver for the target platform. Install the server and a platform driver, start the server, create a driver session with the required capabilities, put setup and cleanup in TestNG lifecycle hooks, and run the tests through your project’s chosen build runner.
The chain is: TestNG invokes a Java test method; the Appium Java client sends WebDriver commands to the Appium server; the server routes them through an installed Android or iOS driver to the selected emulator or device. Appium’s Java client is built on Selenium. The server alone cannot automate a device: as the Appium project explains, “this will only install the core Appium server, which cannot automate anything on its own.” See the Appium project and its official documentation.
1. Prepare the Java project
Use a JDK supported by the Appium Java client and your build tooling. Add the Appium Java client and TestNG as test dependencies. Appium documents Maven’s test scope and Gradle’s testImplementation configuration. Choose versions that are compatible with one another; Appium’s client documentation uses a placeholder version, so check the current client and compatibility guidance rather than copying an unverified version number.
<dependencies>
<dependency>
<groupId>io.appium</groupId>
<artifactId>java-client</artifactId>
<version>YOUR_COMPATIBLE_VERSION</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>YOUR_TESTNG_VERSION</version>
<scope>test</scope>
</dependency>
</dependencies>
For Gradle, add equivalent test dependencies in the project’s dependency block:
dependencies {
testImplementation("io.appium:java-client:YOUR_COMPATIBLE_VERSION")
testImplementation("org.testng:testng:YOUR_TESTNG_VERSION")
}
tasks.test {
useTestNG()
}
The Appium client’s constructors and typed option APIs can change between releases. The sample below uses the RemoteWebDriver-compatible URL and W3C capabilities approach; check the current Java client documentation when selecting a release or adapting it to typed driver options. TestNG documents annotations and suite configuration in its official documentation.
2. Install Appium and the target driver
- Install the Appium server using the method documented for your environment.
- Install the platform driver you need using the Appium extension CLI workflow. For Android, that is commonly UIAutomator2; for iOS, it is commonly XCUITest. Follow the chosen driver’s current prerequisites.
- Prepare an emulator, simulator, or connected device. Install or build the app you intend to test, and note its path or package/bundle details.
- Start the Appium server. The project documents
appiumas the server-start command and port 4723 as the default in its CLI context. Use the actual URL and port configured for your server.
appium
Server installation, driver installation, and device setup are separate. If a session fails before a test begins, inspect the server log and driver prerequisites first. Consult the Appium repository and the selected driver’s current documentation.
3. Set capabilities for a session
A session needs platformName and appium:automationName. Appium-specific capabilities use the appium: prefix under W3C capability conventions. Add only the values appropriate for the app and driver. Capabilities are session-start parameters; changing a Java field after the session begins does not reconfigure the running session.
| Capability | Use |
|---|---|
platformName |
Identify the platform, such as Android or iOS. |
appium:automationName |
Select the platform automation driver, commonly UIAutomator2 or XCUITest. |
appium:deviceName |
Identify a target by the name expected by the driver or device environment. |
appium:udid |
Target a particular connected device when its unique identifier is required. |
appium:platformVersion |
Specify a platform version when needed by the target environment. |
appium:app |
Provide the app artifact path or location accepted by the driver. |
| Browser target | For mobile browser testing, set the browser capability expected by the selected driver instead of an app artifact. |
appium:noReset, appium:fullReset |
Control app-state reset behavior where supported. Their effects are driver-sensitive; validate them for the selected driver. |
Do not assume a capability set works unchanged across Android, iOS, driver releases, or local and hosted devices. Validate driver names, capitalization, accepted capability values, and typed options against the specific client and driver versions. See Appium’s capabilities guide.
4. Create a TestNG test with setup and cleanup
This example starts a fresh session before each test method and quits it after each method. Replace the app path and device details with values for your target. The small assertion is only a placeholder: use a locator and expected app behavior that exist in your application.
package example;
import java.net.URL;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.remote.RemoteWebDriver;
import org.testng.Assert;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
public class MobileAppTest {
private RemoteWebDriver driver;
@BeforeMethod
public void startSession() throws Exception {
DesiredCapabilities caps = new DesiredCapabilities();
caps.setCapability("platformName", "Android");
caps.setCapability("appium:automationName", "UiAutomator2");
caps.setCapability("appium:deviceName", "YOUR_DEVICE_NAME");
caps.setCapability("appium:app", "/absolute/path/to/your-app.apk");
// Add appium:udid or appium:platformVersion when your target requires them.
driver = new RemoteWebDriver(
new URL("http://127.0.0.1:4723"),
caps
);
}
@Test
public void appSessionStarts() {
Assert.assertNotNull(driver, "The Appium session should be available");
// Find an app element and assert meaningful behavior here.
}
@AfterMethod(alwaysRun = true)
public void stopSession() {
if (driver != null) {
driver.quit();
driver = null;
}
}
}
Use alwaysRun = true for cleanup when a test fails, and guard against a null driver if session creation itself throws. For iOS, change the platform, automation name, app target, and device configuration to match XCUITest and the chosen simulator or device. Do not copy Android values into an iOS session.
TestNG lifecycle choices
@BeforeMethodand@AfterMethodprovide method-level setup and cleanup. This gives each test a fresh session and reduces shared-state coupling, at the cost of creating more sessions.@BeforeClassand@AfterClasscan share a session across a class. This reduces repeated setup, but tests must manage app state and ordering carefully.- TestNG also provides test-, suite-, and group-level before/after hooks. Choose the narrowest scope that matches the intended sharing boundary.
- Superclass hooks can be inherited. Check the class hierarchy if setup appears to run more than once or in an unexpected order.
For parallel execution, give concurrent tests distinct devices or sessions and avoid sharing a mutable driver instance across test methods. Device capacity and driver support constrain safe parallelism.
5. Run and organize the suite
A TestNG suite XML file selects tests and classes. For example:
<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd">
<suite name="Mobile suite">
<test name="Android app tests">
<classes>
<class name="example.MobileAppTest"/>
</classes>
</test>
</suite>
You can run TestNG through its command-line runner or through your project’s Maven or Gradle test integration. The exact command depends on the runner plugin and project configuration; there is no single build command that applies to every setup. Configure the runner to use TestNG and point it at the suite file where appropriate, then use that same build entry point in local development and team automation.
6. Choose a target: emulator, device, or hosted environment
| Target | Useful when | Trade-offs to consider |
|---|---|---|
| Emulator or simulator | You want a convenient local target for iteration and already have it configured. | Setup and behavior depend on the local environment; it may not represent device-specific hardware behavior. |
| Physical device | Real hardware behavior, sensors, or a particular device identity matters. | Requires a connected and prepared device; use its identifier when necessary. Buying a device is not required for every workflow. |
| Hosted device environment | You need access to devices or infrastructure managed outside the local workstation. | Consider network dependence, device availability, configuration ownership, and cost. Verify current Appium support and vendor details independently before choosing a service. |
Appium can run locally or in a cloud-hosted setup. The right target depends on which behavior you need to validate and what devices are available; the cited sources do not establish numerical cost or performance comparisons.
7. Or skip the browser setup
Appium and TestNG are for controlling mobile apps. If your test workflow also needs a screenshot of a website, ScreenshotNeo provides a website screenshot API and MCP server. Its API accepts one GET request with a URL and can return PNG, JPEG, WebP, or PDF. See the ScreenshotNeo API documentation.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
ScreenshotNeo removes cookie banners, newsletter popups, and chat widgets before capture. Bot checks, blank pages, and failed loads are never billed. An MCP server lets AI agents use screenshot tools. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000. Sign up for 1,000 free screenshots a month, with no card required.
8. Troubleshooting
| Symptom | Likely cause | What to check or change |
|---|---|---|
| Session cannot be created; server says no matching driver | The server is installed but the platform driver is missing, or the automation name does not match. | Install the driver for the target platform and verify the automation name and capitalization against that driver’s current documentation. |
| Connection refused | The server is not running, or the client URL/port differs from the server configuration. | Start Appium and confirm the host, port, and base path expected by the client and server version. |
| App path or app launch fails | The artifact path is wrong, inaccessible, or not suitable for the selected driver/device. | Use the correct app artifact and path form for the environment; confirm the device can install or access it. |
| Device not found | The target is not available to the driver, or the device identity is ambiguous. | Check that the emulator or device is running and connected, then provide the appropriate device name or unique identifier. |
| Capability rejected | A capability is missing its appium: prefix, has an invalid value, or is unsupported by the driver. |
Review the W3C capability format and the selected driver’s supported capabilities. Keep required platform and automation names present. |
| Tests pass individually but fail as a suite | Tests share app state or a driver/session unintentionally. | Use method-level sessions where isolation matters, reset app state deliberately, and avoid concurrent access to one device or driver. |
| Session remains after a failure | Cleanup was skipped or the session failed before the normal teardown path. | Use an always-run teardown hook with a null check; inspect server logs and stop orphaned sessions during environment cleanup. |
| Build cannot resolve dependencies or compile | Incompatible client, Selenium, TestNG, or JDK versions, or stale API syntax. | Check current Appium client compatibility guidance and update imports/options to match the dependency version actually selected. |
9. Reliability, performance, and cost
- Isolation: A new session per method makes state boundaries clearer, while class-level reuse avoids repeated session creation. Choose based on reproducibility and setup overhead; this is a design trade-off, not a universal speed rule.
- Stability: Keep device identity and app state explicit. Tests that depend on leftover state, unstable device availability, or shared sessions are harder to reproduce.
- Execution capacity: Parallel tests need independent device/session capacity and must not race over shared state. Start with the target environment’s supported concurrency.
- Cost: A local emulator or device and a hosted device service have different infrastructure and access costs. Appium’s sources do not provide a universal cost figure; check the actual environment and any provider pricing.
- Version maintenance: The Appium server, client, platform driver, Selenium dependencies, and TestNG evolve independently. Pin project dependencies and validate upgrades against the chosen driver’s prerequisites.
- Website artifacts: For separate website screenshot needs, ScreenshotNeo bills only clean shots: bot checks/CAPTCHAs, blank pages, timeouts, failed loads, and cache hits cost nothing, with verdict and billing details in response headers. Its cache TTL is configurable.
FAQ
Does TestNG automate the phone?
No. TestNG organizes and runs Java tests and lifecycle hooks. Appium’s client, server, and platform driver provide the connection to the mobile target.
Do I need a physical phone?
No. An emulator or simulator can be a local target when configured. Use real hardware when the behavior under test depends on it.
Can I use the same capabilities for Android and iOS?
Only the general session structure carries over. Platform name, automation driver, app target, and device settings must match the selected platform and driver.
Can ScreenshotNeo capture a mobile app screen through Appium?
ScreenshotNeo captures websites through its screenshot API; it is not a replacement for Appium’s mobile app automation. Use Appium for app screens and ScreenshotNeo when you need a website capture.


