做UI自动化项目已经有一段时间, 这里总结下UI自动化中最为繁琐也是最为重要的一个步骤, 即元素定位, 做UI自动化模拟用户操作app, 首先最重要的的就是能够找到页面上对应的元素, 才能对它进行如点击\双击\长按\滑动等操作.
下面从工具介绍以及定位策略来简单介绍下如何去对一个元素进行定位.
工具 | 支持平台 | 说明 |
---|---|---|
appium-inspector | android,iOS native | 官方appium-desktop安装包自带, 命令行安装没有该工具 |
app-inspector | android,iOS native | 阿里开源的macaca框架带的工具, 可以单独安装:npm install -g app-inspector |
UIAutomatorviewer | android native | android sdk自带工具软件 |
Chrome Inspect | android,iOS webview | android webview可以直接使用, iOS webview需要安装ios-webkit-debug-proxy , 并且以 ios_webkit_debug_proxy -f chrome-devtools://devtools/bundled/inspector.html 启动使用; |
以上4种是非常基础的定位策略,不多做介绍, 其中XPath的定位方式稍微复杂, 读者可以熟悉下xpath的语法, 会有很大帮助;
new UiSelector.resourceId()
, new UISelector.text
, new UISelector.className()
driver.findElementByAndroidUIAutomator("new UiSelector().className(\"android.widget.ImageView\").clickable(true)");
driver.findElementByAndroidUIAutomator("new UiScrollable(new UiSelector().scrollable(true)).scrollIntoView(new UiSelector().textContains(\"测试\"))");
>,<,==,>=,<=,!=
, 范围运算符IN,BETWEEN
, 字符串运算符CONTAINS、BEGINSWITH、ENDSWITH
, 也可以是使用通配运算符LIKE
driver.findElementByIosNsPredicate("type == XCUIElementTypeStaticText AND label CONTAINS '测试' AND enabled == true")
级联调用很好理解, 比如要通过A节点来查找A节点的子节点B, 即driver.findElementsByClassName(“a”).findElementByXpath(“b”);
一般在做UI自动化项目的时候肯定会分层封装, 将页面封装成一个个页面对象, 然后在业务处理代码中直接调用页面对象的方法, appium提供了Page Object design pattern.如下:
@FindBy(id = "list")
@AndroidFindBy(xpath = "//android.widget.ListView")
@iOSXCUITFindBy(iOSNsPredicate = "type=='XCUIElementTypeScrollView'")
MobileElement loanList;
以上代码定义了一个MobileElement loanList
元素,
1. 如果在webview下就是用driver.findElementByid("list")
寻找该元素,
2. 如果在android native下则使用driver.findElementByXpath("//android.widget.ListView")
寻找该元素,
3. 如果在ios native下则使用driver.findElementByiOSNsPredicate("type=='XCUIElementTypeScrollView'")
短短4行代码就解决了跨平台寻找元素的问题, 甚至可以为该元素添加一个@WithTimeout
注解, 为该元素设置一个implicit time, 解决元素加载慢导致的NosuchElementException;
编写好了元素定位的策略之后, 就需要初始化该页面元素对象, appium提供了多种元素初始化的方法, 例如:
PageFactory.initElements(new AppiumFieldDecorator(driver, 1000, TimeUnit.MILLISECONDS), this);
使用该方法即可初始化刚才的元素定位代码, 然后就可以直接操作元素loanList
而无需额外其他操作;
这样一来代码非常简洁清晰, 后期就算元素变化频繁, 也只需要修改元素定位策略的3行代码, 提高了代码的可维护性, 减少了维护成本;