自动化测试 (八) 移动端自动化测试-Appium跨平台方案

张开发
2026/5/12 17:28:11 15 分钟阅读

分享文章

自动化测试 (八) 移动端自动化测试-Appium跨平台方案
移动端自动化测试Appium跨平台方案上篇咱们搞定了Web UI自动化今天进入移动端领域。Appium的slogan是Write once, run anywhere——一套脚本测iOS和Android真的能做到吗一、移动端测试的特殊性移动端和Web端测试有几个本质区别维度Web端移动端运行环境浏览器统一iOS/Android碎片化严重交互方式鼠标键盘触摸、滑动、长按、手势系统权限较少相机、定位、通知、蓝牙等应用类型纯WebNative、Hybrid、WebView安装分发URL访问App Store、应用市场、企业证书所以移动端测试的挑战是环境搭建复杂、设备碎片化、交互方式多样。二、Appium 2.0 架构速览Appium 2.0相比1.x有比较大的架构调整核心是插件化┌─────────────────────────────────────────┐ │ Appium Server 2.0 │ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │ │ uiautomator2 driver │ │ xcuitest driver │ │ │ │ (Android) │ │ (iOS) │ │ │ └─────────┘ └─────────┘ └─────────┘ │ │ ┌─────────┐ ┌─────────┐ │ │ │ 插件系统 │ │ 图像识别 │ │ │ │(element │ │ (opencv)│ │ │ │ wait) │ │ │ │ │ └─────────┘ └─────────┘ │ └─────────────────────────────────────────┘ │ WebDriver Protocol │ ┌──────┴──────┐ │ 测试脚本 │ ← Java/Python/JS和Selenium API类似 └─────────────┘关键变化驱动driver独立安装不再内置支持插件扩展如元素等待插件、图像识别插件更符合W3C WebDriver标准环境搭建# 1. 安装Appium 2.0npminstall-gappium# 2. 安装驱动appium driverinstalluiautomator2# Androidappium driverinstallxcuitest# iOS# 3. 验证appium driver list# 4. 启动服务appium三、第一个Appium测试引入依赖dependencygroupIdio.appium/groupIdartifactIdjava-client/artifactIdversion9.0.0/versionscopetest/scope/dependencyAndroid 测试示例classAndroidLoginTest{privateAndroidDriverdriver;BeforeEachvoidsetUp(){UiAutomator2OptionsoptionsnewUiAutomator2Options().setPlatformName(Android).setDeviceName(Pixel_5_API_33)// 模拟器名称.setApp(/path/to/app.apk)// 待测App路径.setAutomationName(AutomationName.ANDROID_UIAUTOMATOR2).setNoReset(false)// 每次测试重置App状态.setFullReset(false);// 不卸载重装drivernewAndroidDriver(newURL(http://localhost:4723),options);// 隐式等待driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));}AfterEachvoidtearDown(){if(driver!null){driver.quit();}}TestDisplayName(用户登录流程)voidshouldLoginSuccessfully(){// 输入用户名WebElementusernameInputdriver.findElement(AppiumBy.id(com.example.app:id/username));usernameInput.sendKeys(testuser);// 输入密码WebElementpasswordInputdriver.findElement(AppiumBy.id(com.example.app:id/password));passwordInput.sendKeys(testpass);// 点击登录WebElementloginBtndriver.findElement(AppiumBy.id(com.example.app:id/login_btn));loginBtn.click();// 验证登录成功首页出现WebElementhomeTitledriver.findElement(AppiumBy.id(com.example.app:id/home_title));assertThat(homeTitle.isDisplayed()).isTrue();assertThat(homeTitle.getText()).isEqualTo(首页);}}iOS 测试示例classIOSLoginTest{privateIOSDriverdriver;BeforeEachvoidsetUp(){XCUITestOptionsoptionsnewXCUITestOptions().setPlatformName(iOS).setDeviceName(iPhone 14 Pro).setPlatformVersion(17.0).setApp(/path/to/app.app)// iOS app或ipa路径.setAutomationName(AutomationName.IOS_XCUI_TEST).setNoReset(false);drivernewIOSDriver(newURL(http://localhost:4723),options);}TestDisplayName(iOS用户登录)voidshouldLoginOnIOS(){// iOS用accessibility id定位对应iOS的accessibilityIdentifierWebElementusernameInputdriver.findElement(AppiumBy.accessibilityId(username_input));usernameInput.sendKeys(testuser);WebElementpasswordInputdriver.findElement(AppiumBy.accessibilityId(password_input));passwordInput.sendKeys(testpass);WebElementloginBtndriver.findElement(AppiumBy.accessibilityId(login_button));loginBtn.click();// iOS验证WebElementhomeNavdriver.findElement(AppiumBy.iOSClassChain(**/XCUIElementTypeStaticText[label 首页]));assertThat(homeNav.isDisplayed()).isTrue();}}四、移动端特有的交互操作触摸和手势// 点击和Web一样element.click();// 长按newTouchAction(driver).longPress(LongPressOptions.longPressOptions().withElement(ElementOption.element(element)).withDuration(Duration.ofSeconds(2))).release().perform();// 滑动上滑、下滑、左滑、右滑Dimensionsizedriver.manage().window().getSize();intstartXsize.width/2;intstartY(int)(size.height*0.8);// 从底部80%位置intendY(int)(size.height*0.2);// 滑到顶部20%位置newTouchAction(driver).press(PointOption.point(startX,startY)).waitAction(WaitOptions.waitOptions(Duration.ofMillis(500))).moveTo(PointOption.point(startX,endY)).release().perform();// Appium 2.0 推荐用 W3C ActionsPointerInputfingernewPointerInput(PointerInput.Kind.TOUCH,finger);SequenceswipenewSequence(finger,1).addAction(finger.createPointerMove(Duration.ZERO,Origin.viewport(),startX,startY)).addAction(finger.createPointerDown(MouseButton.LEFT.asArg())).addAction(finger.createPointerMove(Duration.ofMillis(500),Origin.viewport(),startX,endY)).addAction(finger.createPointerUp(MouseButton.LEFT.asArg()));driver.perform(List.of(swipe));系统级操作// 隐藏键盘iOS常用driver.hideKeyboard();// 按设备按键((AndroidDriver)driver).pressKey(newKeyEvent(AndroidKey.BACK));((AndroidDriver)driver).pressKey(newKeyEvent(AndroidKey.HOME));// 打开通知栏Android((AndroidDriver)driver).openNotifications();// 切换网络状态飞行模式、WiFi等((AndroidDriver)driver).toggleAirplaneMode();((AndroidDriver)driver).toggleWifi();// 获取设备信息StringdeviceTimedriver.getDeviceTime();MapString,StringsessionDetailsdriver.getSessionDetails();五、Hybrid App 和 WebView 测试很多App内嵌了Web页面比如H5活动页需要切换到WebView上下文来操作。TestDisplayName(App内WebView操作)voidshouldInteractWithWebView(){// 1. 先进入Native App的某个页面driver.findElement(AppiumBy.id(com.example.app:id/h5_button)).click();// 2. 获取所有上下文NATIVE_APP 和 WEBVIEW_xxxSetStringcontextsdriver.getContextHandles();System.out.println(可用上下文: contexts);// 输出: [NATIVE_APP, WEBVIEW_com.example.app]// 3. 切换到WebView上下文driver.context(WEBVIEW_com.example.app);// 4. 现在可以用Web的定位方式操作H5页面了WebElementh5Buttondriver.findElement(By.cssSelector([data-testidh5-submit]));h5Button.click();// 5. 操作完切回Nativedriver.context(NATIVE_APP);// 6. 继续操作Native元素WebElementnativeElementdriver.findElement(AppiumBy.id(com.example.app:id/result));assertThat(nativeElement.getText()).contains(成功);}注意WebView调试需要App开启setWebContentsDebuggingEnabled(true)而且ChromeDriver版本要和WebView版本匹配。六、Page Object 模式在移动端和Web端一样移动端也需要Page Object来封装。publicclassLoginPage{privatefinalAppiumDriverdriver;privatefinalWebDriverWaitwait;// Android和iOS的定位策略不同用FindBySetOf定位AndroidFindBy(idcom.example.app:id/username)iOSXCUITFindBy(accessibilityusername_input)privateWebElementusernameInput;AndroidFindBy(idcom.example.app:id/password)iOSXCUITFindBy(accessibilitypassword_input)privateWebElementpasswordInput;AndroidFindBy(idcom.example.app:id/login_btn)iOSXCUITFindBy(accessibilitylogin_button)privateWebElementloginButton;publicLoginPage(AppiumDriverdriver){this.driverdriver;this.waitnewWebDriverWait(driver,Duration.ofSeconds(10));PageFactory.initElements(newAppiumFieldDecorator(driver),this);}publicLoginPageenterUsername(Stringusername){wait.until(ExpectedConditions.visibilityOf(usernameInput));usernameInput.clear();usernameInput.sendKeys(username);returnthis;}publicLoginPageenterPassword(Stringpassword){passwordInput.clear();passwordInput.sendKeys(password);returnthis;}publicHomePagetapLogin(){loginButton.click();returnnewHomePage(driver);}publicHomePageloginAs(Stringusername,Stringpassword){returnenterUsername(username).enterPassword(password).tapLogin();}}关键点用AndroidFindBy和iOSXCUITFindBy分别定义两个平台的定位策略一套Page类同时支持Android和iOS。七、测试稳定性提升移动端测试比Web端更容易不稳定常见问题和解决方案问题1元素还没加载就操作了// ❌ 直接找可能还没出现driver.findElement(AppiumBy.id(xxx)).click();// ✅ 显式等待WebDriverWaitwaitnewWebDriverWait(driver,Duration.ofSeconds(10));wait.until(ExpectedConditions.elementToBeClickable(AppiumBy.id(xxx))).click();// ✅ 更稳健等动画结束wait.until(d-{try{WebElementeld.findElement(AppiumBy.id(xxx));returnel.isDisplayed()el.isEnabled();}catch(Exceptione){returnfalse;}});问题2弹窗干扰// 处理随机弹窗权限请求、升级提示等publicvoiddismissRandomPopup(){ListBypopupButtonsList.of(AppiumBy.id(com.example.app:id/btn_cancel),AppiumBy.id(android:id/button2),// 系统对话框的取消AppiumBy.xpath(//android.widget.Button[text允许]),AppiumBy.xpath(//android.widget.Button[text以后再说]));for(Bylocator:popupButtons){try{WebElementbtndriver.findElement(locator);if(btn.isDisplayed()){btn.click();return;}}catch(NoSuchElementExceptione){// 没找到继续下一个}}}// 在每个操作前调用BeforeEachvoiddismissPopups(){dismissRandomPopup();}问题3键盘遮挡输入框// iOS经常遇到键盘弹起遮挡问题publicvoidsafeSendKeys(WebElementelement,Stringtext){element.click();// 先点击聚焦// 如果是iOS先隐藏键盘if(driverinstanceofIOSDriver){try{driver.hideKeyboard();}catch(Exceptione){// 键盘可能没弹出忽略}}element.sendKeys(text);}八、真机 vs 模拟器怎么选维度模拟器/仿真器真机成本低免费高设备采购/云真机启动速度Android快iOS慢不用启动系统版本可随意切换固定硬件特性不支持相机、指纹、NFC等完整支持性能表现和真机有差异真实稳定性高受网络/电量等影响建议开发调试用模拟器快自动化回归用云真机平台Sauce Labs、BrowserStack、阿里云真机硬件相关测试必须用真机九、小结今天咱们聊了移动端自动化的核心内容主题要点Appium 2.0架构插件化、驱动独立安装、W3C标准Android/iOS测试UiAutomator2和XCUITest驱动定位方式略有不同手势操作TouchAction/W3C Actions实现滑动、长按等WebView测试切换上下文context操作H5页面Page ObjectAndroidFindBy iOSXCUITFindBy一套代码双平台稳定性显式等待、处理弹窗、键盘遮挡真机vs模拟器开发用模拟器回归用云真机一句话总结Appium确实能做到一套脚本双平台但需要处理好定位差异和稳定性问题。移动端测试维护成本高优先覆盖核心用户路径。

更多文章