Review and Stretch Goals

5 min read

The capstone is complete when the full test suite runs reliably on both platforms, with screenshots on failure, Allure reporting, and CI integration. This lesson covers the self-review checklist, common final mistakes, and where to take your skills next.

Self-review checklist

Work through each item before considering the capstone done:

Project structure

  • DriverManager uses ThreadLocal<AppiumDriver> — no shared static fields
  • BaseTest starts/stops the Appium server in @BeforeSuite/@AfterSuite
  • Driver is created in @BeforeTest, destroyed in @AfterTest
  • Page objects extend BasePage and have no assertions
  • Tests extend BaseTest and have no locators

Locators

  • All locators use accessibilityId, UIAutomator, or predicate strings
  • No XPath used (if any XPath exists, document why)
  • Locator constants are private static final By
  • No hardcoded coordinates (except in GestureUtils)

Waits

  • No Thread.sleep() anywhere in the codebase
  • waitForVisible and waitForClickable used in page objects
  • Loading spinners are waited on before asserting on results

Parallelism

  • testng-smoke.xml runs Android and iOS simultaneously
  • Each @BeforeTest receives platform parameter from XML
  • Test output shows two concurrent sessions in the Appium log

Reporting

  • ScreenshotListener saves PNG to target/screenshots/ on failure
  • RetryTransformer is listed in testng.xml listeners
  • @Epic, @Feature, @Story visible in Allure report
  • @NoRetry applied to the checkout test (or wherever retry would cause duplicate orders)

CI

  • testng-smoke.xml completes in under 3 minutes on GitHub Actions
  • Allure results are uploaded as a workflow artifact
  • No credentials in committed code (environment variables only)

Common final mistakes

Driver leak on test failure: If a test fails mid-setup (before the driver is fully ready), @AfterTest may try to quit a null driver. Guard against it:

@AfterTest
public void tearDown() {
    AppiumDriver driver = DriverManager.getDriver();
    if (driver != null) {
        driver.quit();
        DriverManager.removeDriver();
    }
}

Shared page object state: Creating a page object in @BeforeClass and reusing it across test methods means method B inherits any state mutation from method A. Always construct fresh page objects in @BeforeMethod or at the start of each test.

Appium server still running after suite: If AppiumServiceBuilder throws during startup and the server partially started, @AfterSuite may not clean it up. Add a JVM shutdown hook as a safety net:

@BeforeSuite
public void startServer() {
    AppiumServer.start();
    Runtime.getRuntime().addShutdownHook(new Thread(AppiumServer::stop));
}

Flaky scroll tests on CI: Emulators in CI have lower frame rates than local machines. Scroll gestures that work locally may overshoot or undershoot. Increase the gesture duration and reduce scroll distance on CI:

boolean isCI = Boolean.parseBoolean(System.getenv("CI"));
Duration scrollDuration = isCI ? Duration.ofMillis(1000) : Duration.ofMillis(500);

What comes next

XCUITest for iOS-native deep dives

Appium's iOS support is excellent, but XCUITest gives you access to performance metrics, accessibility audits, and Xcode's recording tools that Appium can't reach. If your app is iOS-first, add an XCUITest target for the scenarios that need native precision.

Espresso for Android in-process testing

Espresso tests run in the same process as the app, which means they see private state, synchronise automatically with the main thread, and run 5–10× faster than Appium. Use Espresso for unit-level UI tests that don't need cross-platform parity.

Device farms at scale

The BrowserStack setup from Chapter 6 handles 4 devices. For 40 devices, you need a real parallelism strategy: shard the test suite by feature area, run each shard on a dedicated device, and aggregate Allure results after all shards complete.

Performance baselines

The next quality problem after functional coverage is performance regression. Measure cold start time, frame drops during scroll, and memory usage under load. Add assertions: if cold start exceeds 3 seconds, the test fails.

Accessibility scanning

Appium's mobile: accessibilityAudit command (iOS) and the Accessibility Test Framework for Android can scan the current screen for WCAG violations. Add a scan to each page object's constructor and log violations to the Allure report.

These specialisations are covered in the Mobile Testing roadmap path — the Appium foundation you've built here is the prerequisite for all of them.

// tip to track lessons you complete and pick up where you left off across devices.