前言
做或不做?
最新在做一些移动端UI自动化的工作,已经有一些成果.本次记录一下如何从0搭建UI自动化框架.
UI自动化在初创公司都不太被看好,原因有以下几点:
- 1.功能经常改,可能一个功能模块下个版本就没有了.
- 2.UI自动化需要专职的人写,有一定的投入成本.
- 3.UI自动化发现不了什么问题,存在意义不大.
- 4.其他
上述几点,目前移动端UI自动化在中小公司还没有开展或者开展的不是很好.但是随着项目发版的频率越来越高,每次发版前回归核心功能的手工测试工作量越来越大.
带来的是问题是,每次临近发版本,开发每次build一个包,测试同学就要对所有功能check一遍,毕竟临近发版不敢仅回归改动的地方,要回归所有功能.
所以移动端UI自动化还是有一定的存在必要的,只不过看公司项目的发展,一般来说项目较为稳定做比较合适.
误区
关于UI自动化能带来多少价值,这个话题一直比较有争议.
误区有以下几点:
- 1.不能替代手工测试
- 2.必须发现bug
- 3.其他
价值
体现UI自动化的价值有以下几点:
- 1.能减轻部分手工测试,比如核心模块.
- 2.持续集成中,对每次build的app的核心模块做冒烟测试.
- 3.持续集成中,结合性能测试.
框架选择
接触UI自动化也大概有3年左右时间了,从Robotium、Appium、Macaca到最近比较火的atx都有接触过.但是Appium在解决平台兼容性、使用规模大、文档较多相比其他框架还是有较大的优势.
当然框架的选择也是因人而异,没有绝对好和坏.
开发环境
- 语言: java jdk1.8
- 编译环境:maven
- 框架:testng
- 报告:extentreports
- IDE:idea
- appium client:java-client
- appium server:1.9.0-beta.1
框架设计
先附上一张模块图
兼容
这里指的兼容性是要兼容Android主流系统和iOS主流系统.
比如Android在大于等于7.0系统,底层引擎需要使用uiautomator2,不然在获取元素会存在问题.
比如iOS底层使用是xcuitest,wda是和xcuitest进行通信.但是只有大于等于9.3版本底层才使用的xcuitest.
综上在框架设计前期,不仅需要考虑单点系统,而是需要考虑框架的能兼容多少设备版本.
复用性
现在移动端都是做Android和iOS两端,所以UI自动化也需要写两端的代码.做Android和iOS唯一不太一样的是元素定位不同,其他driver实例和公共方法调用,基本上可复用的.
后续维护
好的框架设计可以减轻后续维护成本,这里最常见的是PO封装,使模块代码和测试代码分离.
之前写的PO设计文章 https://testerhome.com/topics/15717
页面建模
把app每个页面或者多个关联的页面抽象出一个page
- 首页底部tab导航,可提供中转功能
- 首页大类入口,可提供中转功能
- 首页搜索,可单独封装成一个方法
- 并不是页面中所有的都要建模,优先核心功能
在建模页面中,appium提供页面工程模式(PageFactory)
代码语言:javascript复制PageFactory.initElements(new AppiumFieldDecorator(driver), HomePage);
需要driver参数和当前类参数初始化当前页面
元素操作
元素定位
appium提供注解的方式声明元素,并且声明显示等元素时间
代码语言:javascript复制@FindBy( xpath = ".//*[@text='发现']")
@WithTimeout(time = Timeout,chronoUnit = ChronoUnit.SECONDS)
public AndroidElement HomeBtn;
需要注意的是iOS元素定位的方式不是很多,优先用accessibility,万不得已采用xpath,xpath定位比较慢.
元素操作
在上边定义元素,可以直接使用click或者sendkeys操作
把homeTab封装成一个小方法,可在其他page或者case中调用
代码语言:javascript复制/**
* 首页tab
*/
public void homeTab() throws InterruptedException {
HomeBtn.click();
log_info("点击首页");
}
用例编写
用例编写应该有几个原则:
- 每个用例步骤不易太多,太多会让case的成功率变低,应该把多步骤分摊到多个case中
- 解耦case之间的关系,比如case1的运行结果不能影响case2执行.需要使用testng的执行顺序
- 也就是在每个test方法,都重新重新走一次BeforeMethod方法,虽然脚本执行的整体时间增长了,但是case的稳定性会增加
@BeforeMethod
public void setup() throws IOException, InterruptedException
baseDriver = driver.preiOSDriver();
}
case应该直接调用page中的方法,让case变得更简洁
代码语言:javascript复制/**
* 测试点:首页-商城
*/
@Test(enabled = true)
public void test_shop() throws InterruptedException {
homePage.homeShop();
}
断言
使用testng的Assert类,可以封装一些简单的断言.
代码语言:javascript复制 /**
* 断言页面包含某个的元素
*/
public void assertContain(String text) throws InterruptedException {
PageSource = this.driver.getPageSource();
if (PageSource.contains(text)){
Assert.assertTrue(true);
}else {
Assert.assertFalse(true);
}
}
/**
* 断言页面包含element
* by:元素
*/
public void assertContainBy(By by){
if (driver.findElements(by).size() > 0){
Assert.assertTrue(true);
}else {
Assert.assertFalse(true);
}
}
需要注意的是,点击页面跳转以后,如果立即断言会断言失败,因为页面跳转一般是由1~3秒的页面加载,这个时候元素还没有呈现加载处理,如果获取页面元素进行断言必然会抛异常.
解决方法大致可以在每个前言加等待时间或者设置断言超时时间
失败截图
如果case中使用了断言方法,在运行多条case以后,肯定是关心case的成功或者失败,失败具体是什么原因或者当时失败的页面状态.
testng框架TestListenerAdapter类提供了成功、失败等状态的监听方法
那么可以写个类集成TestListenerAdapter方法,扩展onTestFailure方法.比如实现失败截图,可以使用base64方法把图片输出到测试报告中
测试报告
关于选用测试报告插件,testng提供了测试报告,但是不太美观.也可以使用reportng,也仅仅比testng稍微好看点.
推荐两个比较好的测试报告框架,Allure和extentreports.我目前使用的是extentreports,大致生成测试报告如下
运行
因为使用的maven,在pom中使用了maven-surefire-plugin插件,可以动态传入参数.比如运行平台、设备id、appium端口等.
另外已经把appium server做成自启动,也不需要额外启动.
代码语言:javascript复制外部参数传入执行:
PLATFORM:设备平台 Android or iOS
UDID:设备UDID
APPIUMPORT:appium的端口
WDAPORT:wda的端口
MAILLIST:收件人地址 xxxx@163.com
mvn test -DPLATFORM=Android -DUDID=192.168.56.101:5555 -DAPPIUMPORT=4723 -DBPPORT=4724 -DWDAPORT=8003 -DMAILLIST= xxxx@163.com, xxxx@163.com
持续集成
- 和jenkins结合,每次打包或者发版前把build的包进行UI自动化回归测试
- 自动化任务调度,在前端页面触发UI自动化,后端执行UI自动化脚本