Appium UI 自动化到底要不要用 Page Object 模式,以及 yaml 数据驱动?

zzt · July 11, 2019 · Last by zailushang replied at July 17, 2019 · 1436 hits

业务背景

我这是一家手游公司, 前端使用unity,appium之类框架的都无法识别unity控件,最后得知网易airtest下面的poco框架可识别unity控件。
由于之前没有相关经验靠自己摸爬滚打,走了很多弯路,代码结构/框架也重构了几次(现在还想重构😂 )。
在设计之初有过很多构想,觉得应该满足那些要求:

  • 颗粒度尽可能小且case互不影响
  • 可根据不同策略执行不同深度case集
  • 负载均衡:收集可用测试机根据对应测试机执行快慢分发不同数量case任务
  • 重复执行
  • 失败重试 (因业务特殊目前不准备失败重试,因为case前置数据准备是通过跑sql修改数据,但前端不会及时刷新,需要找到一个刷新点,主流的刷新点是重登, 从当前case界面-》跳转游戏主界面-》设置切换账号-》登录界面登录账号-》跳转游戏主界面-》跳转case指定界面,这个过程非常耗时,会大幅增加case执行时间)
  • 让case编写者只需要关注业务
  • 以最小的改动面对未来需求的变化
  • ............... 还实现了很多哈 不一一列举

问题介绍

UI自动化到底要不要用Page Object模式,以及yaml数据驱动? 或者说我这个情况要不要使用po模式?

了解到Page Object模式很主流,很火。然后使用yaml数据驱动,很炫酷,高大上的样子 (想立马就应用到项目中)
但任何技术最终还要是服务于业务,是要能解决某些或某类问题
这里以我对po模式非常浅显的理解和我当前的做法做了个对比:

po模式 当前搞法
代码量 多 两倍以上
复杂度 较复杂 简单明了
ui变化 修改简单 修改简单

单看表格可能看不懂哈,直接贴python代码如下:

省去了case前置界面准备,前置数据准备

代码内容大概是把一个战术技能从0级升级到10, 并做相关断言

data_0 = [
['0', '每有一个进攻战术达到<color=#fca926>10</color>,\n球队进攻<color=#fca926>+0</color>', '1', '15001', 9],
['1', '每有一个进攻战术达到<color=#fca926>10</color>,\n球队进攻<color=#fca926>+1</color>', '2', '15002', 9],
['2', '每有一个进攻战术达到<color=#fca926>10</color>,\n球队进攻<color=#fca926>+2</color>', '4', '15003', 9],
['3', '每有一个进攻战术达到<color=#fca926>10</color>,\n球队进攻<color=#fca926>+4</color>', '6', '15004', 9],
['4', '每有一个进攻战术达到<color=#fca926>10</color>,\n球队进攻<color=#fca926>+6</color>', '9', '15005', 9],
['5', '每有一个进攻战术达到<color=#fca926>10</color>,\n球队进攻<color=#fca926>+9</color>', '12', '15006', 9],
['6', '每有一个进攻战术达到<color=#fca926>10</color>,\n球队进攻<color=#fca926>+12</color>', '16', '15007', 9],
['7', '每有一个进攻战术达到<color=#fca926>10</color>,\n球队进攻<color=#fca926>+16</color>', '20', '15008', 9],
['8', '每有一个进攻战术达到<color=#fca926>10</color>,\n球队进攻<color=#fca926>+20</color>', '25', '15009', 9],
['9', '每有一个进攻战术达到<color=#fca926>10</color>,\n球队进攻<color=#fca926>+25</color>', '30', '15010', 9],
['10', '每有一个进攻战术达到<color=#fca926>10</color>,\n球队进攻<color=#fca926>+30</color>', '0', '0', 0],
]
@allure.story('战术素养')
@allure.title('升级常规进攻素养0-10级')
@pytest.mark.parametrize('level, des, number, style, t_book', data_0)
def test_0(self, mt, level, des, number, style, t_book):
poco = mt.poco
poco("Content").child("TacticsStyleItem(Clone)")[0].click() #选中常规进攻素养
assert poco("Content").child("TacticsStyleItem(Clone)")[0].child('GiftType').get_text().split('.')[1] == level
#检查当前进攻素养的等级是否正确
assert poco("DetailPanel").child("CurrentEffect").child('Desc').get_text() == des #断言当前进攻素养的文案内容是否正确
if level != '10':
poco("UpgradePanel").child("UpgradeBtn").click() #点击升级按钮
poco("Content").child("TacticsStyleItem(Clone)")[0].click() #点击跳过动画
assert mt.sql.select(SQL_1_0+style)[1][0] == t_book, SQL_1_0+style #查看数据库对应类型道具应该减少一个
assert poco("CurrentEffect").child('Desc').get_text().split('+')[1].split('<')[0] == number #升级后加成的数值是否正确
else:
assert poco("UpgradePanel").child("UpgradeBtn").child("Label").get_text() == "已满级" #满级时应不能升级

疑惑

这样看来,po模式会更加繁琐,笨重,好像po模式没有什么优势。 请有这方面经验的朋友解惑一下

共收到 20 条回复 时间 点赞

PO只是解耦和提高控件复用性吧,至于复杂度这个和业务、你的测试用例都有关系。

楼主你这个代码就像单身汉的屋子一样,哪怕乱如麻也能很快找到要找的东西,因为你已经非常熟悉了。但是在多人协作的时候,你这个代码就不忍直视了,一坨一坨的堆积在一起无从落脚。
再说PO,其实PO设计模式是一种指引,而不是枷锁。在指引的帮助下可以很好的帮助我们梳理项目结构,优化层级,让协作更流畅,新人上手更容易,维护起来更方便。但是楼主提到的业务情况也会存在特殊性,比如我们之前也纠结过“断言要不要放到test方法里面”,“业务方法到底拆到什么颗粒度”,元素剥离、数据分离、方法分层到底收益如何度量,这些经历过阵痛的人会理解的更加深刻一些。

zzt #3 · July 11, 2019 作者
simple 回复

多谢 ,回答的详细,但感觉还是没get到点哈。可能还需要更多坑的洗礼才会明白😂

"UI自动化到底要不要用Page Object模式,以及yaml数据驱动 " 建议你不要在意这些,这些也就是之前写自动化人的自己的规范而已,不可一叶遮目,就像SQL范式官方的范式,实际的开发有多少人遵循了;

你想怎么写 就怎么写, 怎样爽怎么来,

说真的,你这个可维护性和工作量真的很大,到后面说不定都很难搞下去,我建议你们还是将页面元素抽离分装一层,编写用例者只关心业务,环境这一块也有用例本身去控制,这样效果会比较好,用例格式统一,封装格式统一,复用性强,即使不会写代码的人也会很容易上手,一旦某个控件元素有调整了只需要修改封装的几个接口就行了,除非大面积改动才改用例,底层处理好后,一个项目不到2个人很快就可以搞起来的,我这边是这么实施的,也是游戏哈

我觉得po模式比较注重可复用性吧,多人写脚本的时候,重复的部分都可以提取做公共模块,新人接手的时候上手也比较快

zzt #7 · July 12, 2019 作者

恩 以务实为主, 但想把框架设计的更好,就还是需要借助外界 行业的力量 碰到好的思路 方法 就想看能不能把它融入到项目中

zzt · #8 · July 12, 2019 作者
Author only

为啥不用airtest呢

zzt #10 · July 12, 2019 作者
张全蛋 回复

感觉图片识别 准确率 和效率 都是瓶颈 另外case多了后 海量图片的储存都很担忧 , 所有没有使用airtest下面的图片识别 只用了poco

zzt 回复

游戏的话可能变化比较快,不太适合用图像识别做测试,我们的业务还挺稳定的,基本上两周维护一下就行了,图片不会变

没有最好的设计,大部分情况只需要够用的设计。如果你觉得目前的设计没遇到什么大问题,沿用就好。

po偏设计模式,主要应用在大量用例、协作写脚本比较多的场景,用尽量少的额外成本,解决这个场景下不好协作维护的问题。
从楼主的说明看,用例不多、协作也基本没有,不必强求。

用例多了 Page Object 更好(实际能写很多的情况很少)
多人开发 Page Object 更好(实际很多人写的情况很少)
抽象成 Page Object 复用性可读性更好(实际抽象的很差复用性可读性很差)
UI 改动频繁 Page Object 修改起来更快(实际和全局搜索替换差不多)
……
即使需要更高的抽象了, Page Object 或者数据驱动也只是方向之一。
这和开发论坛上常见的轻量重量框架之争差不多,能清楚的了解场景,然后根据场景做合适的选择才是困难的地方。

好几年前开始学 UI 自动化的时候,到处都在教 Page Object ,就跟着这样写咯。后来听 SAP 的人分享端到端自动化,说他们有两万多的用例……

我个人倾向bot-style,对PO的那些优势实在毫无感觉,因为我还没遇到需要协作的情况,就算我的子模块有8K的case那也是我自己写,无法指望别人来帮忙的……我觉得需要协作本质上是模块之间的耦合在自动化测试的数据依赖上没处理好而已~所以面向业务的线性脚本才是我的心头爱~

  • 我觉得 po 最主要的作用不是解耦,因为测试流程里面包含了很多页面状态,其他人想复用是不太可能的,对单独的某一个人来说可能能提高代码复用率,我的理解最重要的作用是便于代码维护,因为可能经常需要修改
  • 数据驱动的方式有很多种,看哪种方式合适就用哪种
zzt #16 · July 15, 2019 作者
陈恒捷 回复

用例数量:

哈哈, 用例数量其实还挺多的,游戏业务较复杂,大多时间花费在前置数据准备,目前一共有三四十个模块, 一个模块大概有八九十条左右(模块大小数量也不一定,在case稳定性允许的前提下尽可能覆盖更广更深,所以各种异常情况也会覆盖)。已写完十几个模块,五台手机一起跑大概一小时左右跑完,预计所有case写完后 8台机器一跑 两三小时的样子

设计问题

当前设计暂时还没发现什么大问题,相反现在的case如果有异常可以直接copy代码到airtest IDE里面快速调试很方便。

协作

按照我的计划,可能两人一组负责前期case的堆积(迭代了好几年的项目),后期留下一人维护

就像webmvc模式一样,代码量大了就会知道解耦的好处

槽神 回复

bot-style 是啥?查了好像很少资料。PO设计模式倒是用过。

zzt 回复

那你现在的设计应该可以满足了。不用太纠结 PO 。

zzt [Topic was deleted] 中提及了此贴 16 Jul 20:43
simple 回复

希望分享一篇,目前正在阵痛中

需要 Sign In 后方可回复, 如果你还没有账号请点击这里 Sign Up