Source: TesterHome Community
In the mobile internet landscape, UI test automation remains one of the most widely debated topics within global QA and testing communities. When automation comes up in conversations between test engineers, one question almost always takes priority: Which framework should teams adopt — Appium or Robotium?
From real-world implementation experience, UI automation frequently delivers a relatively low return on investment (ROI). Even so, it closely replicates real manual end-to-end testing workflows. For teams rolling out Test Left strategies to boost overall testing efficiency, UI automation acts as the most approachable starting point. It also creates a clear technical growth pathway for black-box testers looking to upgrade their technical capabilities.
I dedicated more than one year to building and running UI automation pipelines alongside daily functional testing work. During this period, recurring obstacles nearly convinced me to abandon automation entirely:
These ongoing challenges once forced me to reconsider the core value of UI automation. Is automation merely a technical tactic for testers to escape repetitive manual testing and advance their careers?
To systematically resolve these obstacles, I categorize all common pain points into three distinct groups: architectural design flaws, unstable test execution environments, and inconsistent scripting standards. A well-designed framework architecture addresses many root-cause issues. A stable runtime environment drastically reduces ongoing maintenance workload. Standardized scripting rules significantly improve the consistency of test suites. Solving these three categories of challenges enables teams to build stable, low-maintenance, high-throughput UI automation systems.
Common frustrations such as UI changes breaking newly written scripts and native framework failures disrupting test suites stem from flawed foundational architecture. Developing UI automation scripts requires the same strict engineering standards as product feature development. Robust underlying architecture is non-negotiable.
This section covers tool selection and layered framework design, using UiAutomator as the primary practical example.
Public demo samples for UiAutomator, Espresso and other automation frameworks are intentionally simplified. They only showcase three core capabilities: locating UI elements, simulating user interactions, and verifying expected results. If teams build production test suites directly based on these minimal sample projects, large-scale refactoring will become unavoidable at a later stage.
Espresso serves as a clear example: When developers update a single resource ID such as action_save, and this locator appears across 30 independent test steps, testers must manually modify every relevant line of code. Repeating verbose syntax like onView(withId(xxx)).perform(click()) across hundreds of test cases creates substantial unnecessary code redundancy.
These two design practices resolve most architecture-related automation challenges I have encountered. Originating within the Selenium community, the Page Object Model aims to eliminate duplicate code. When UI elements get updated, modifications only need to be applied within a limited set of page classes.
After restructuring code into separated layers, project directories will clearly distinguish page abstractions, shared base utilities and independent business test cases. Comparing click logic for the “One-Tap Boost” button before and after POM adoption highlights major improvements to code readability and long-term maintainability.
Key benefits of this layered architecture:
MainPage, SoftwareManagerPage, WiFiManagerPage). When a feature’s UI undergoes revisions, engineers can quickly identify which page objects require adjustments.Android resource obfuscation creates another widespread architectural barrier. For example, within a mobile security app’s production build, UiAutomator Viewer may identify the “One-Tap Optimize” button using the meaningless obfuscated ID o3, while the original development-defined ID is optimize_button.
Two commonly used makeshift solutions accumulate heavy long-term technical debt:
o3 directly inside automation scripts. Code becomes unreadable, and obfuscated IDs regenerate with every new build, breaking all associated locators.Static fields annotated with @FindBy inside page objects do not initialize when the class loads. Instead, a pre-execution hook dynamically populates all locator fields during runtime:
@FindBy annotation to corresponding fields.Persistent ADB disconnections, intermittent element lookup failures, unexpected OEM system popups and slow screenshot commands all originate from unstable test environments.
ADB instability can be triggered by inconsistent power supply, conflicts with third-party mobile management software, mismatched versions between ADB and Android OS, and internal ADB process crashes. Rewriting ADB from scratch carries excessive engineering costs, so teams should focus on implementable mitigation strategies:
Permission dialogs represent one of the most persistent pain points for mobile UI automation. OEM manufacturers including Huawei, Xiaomi and Oppo implement customized permission popups that appear randomly during test cycles. Embedding popup processing logic directly within business test cases bloats scripts and introduces flaky test behavior.
UiAutomator’s UiWatcher mechanism fully separates popup processing from primary business test workflows. Implementation logic follows these rules:
@BeforeClass or custom RunListener hooks. Execute runWatchers() before launching every business test case.removeWatcher().Standard watchers cannot handle certain synchronous permission scenarios, such as enabling device Wi-Fi. The setWifiEnabled() API blocks execution until users interact with popup windows. For these edge cases, start a background thread before invoking the API. The background thread waits for dialog rendering and triggers confirmation clicks asynchronously.
A familiar challenge for automation engineers: test cases pass consistently during local debugging but fail repeatedly inside daily CI pipelines. This inconsistency almost always originates from non-standard scripting practices. Refining these small details creates a clear divide between unstable execution and dependable test results.
Automation executes strictly based on predefined logic and cannot validate untaken conditional paths. If test cases contain if/else branches, unexecuted logic paths remain unvalidated and create hidden production risks. Teams should separate distinct user flows into fully independent test cases instead.
A foundational automation principle: every valid test case must include three core steps: element discovery, user interaction, and explicit assertion. Test cases without validation deliver zero practical testing value.
TestNG’s dependsOnMethods annotation tempts engineers to build chained test workflows. However, tight case coupling creates severe long-term maintenance burdens. Fully isolated test cases deliver major advantages:
While mainstream automation frameworks provide built-in explicit wait APIs for element visibility, timeout failures remain common. A reusable generic polling waitCondition method outperforms rigid Thread.sleep() hard waits and eliminates unnecessary idle execution time.
Hardcoded pixel coordinates stop working across devices with different screen resolutions and physical sizes. The long-term optimal solution is pushing development teams to assign stable unique IDs and accessibility labels to all interactive UI components.
Even so, coordinate-based interaction cannot always be avoided under three typical scenarios:
Even in these scenarios, avoid raw absolute coordinate calls such as mDevice.click(100, 200). Two stable alternative approaches exist:
Sample code for clicking the screen’s bottom-center area:
mDevice.click(screenWidth / 2, screenHeight * 80 / 100);
UI automation is easy to learn yet notoriously difficult to operate reliably. Engineers can master UiAutomator or Espresso fundamentals within two weeks. The core workflow consists of three repeated actions: locate UI elements, simulate user or device operations, and assert expected UI states.
Building high-value, low-maintenance automation suites requires rigorous engineering discipline. Every challenge covered in this article can be addressed via two core strategies: implement temporary workarounds, or deliver permanent root-cause fixes.
Article length constraints prevent coverage of every edge case encountered during UI automation. Even so, all troubleshooting approaches ultimately fall into the two strategies outlined above: bypass obstacles, or resolve issues at the root.