前段时间用的UI自动化测试框架主要是两个:Macaca和Appium。后来基于了非常多的原因,还是用了大家都用的Appium(这家伙对iOS10支持非常不好)。如果你刚接触这两个包装着Mocha的测试框架,而且想用Node去写整个测试框架,都会发现它们共同的毛病:慢,卡,不稳定,代码不方便阅读等等。这些是很多原因造成的,比如之前用Macaca写登录脚本是一长串Promise。
测试用例写出来后,在模拟器上跑着还不稳定,上一次用例通过了,这一次用例失败了,加上测试速度,格外让人蛋疼。后来经过大神指点迷津,在书写方式和架构上面进行了修改,整个项目看起来清爽不少。
一番改造后,抛弃了Promise,使用Generator和yield,最后的要点就是人们常说的“高耦合,低内聚”。
1.yiewd
Appium下编写测试用例遵循WebDriver协议,Node下可以用wd,而在yiewd在wd外面包了一层,这样你就可以编写更加直观的代码了,解决异步编程问题不是用Promise,而是用Generator。
2.项目架构
项目结构我改了很多遍,效果都不理想:每个测试用例间如果有相互依赖,一个挂了,下面的接着挂了。然后参考这篇文章,对项目进行了改造:
|----app·····················放置各个版本app
|----src
| |----cases············测试用例
| |----screen···········Screen类
| |----util·················工具类
|----cap.js·················环境配置
|----client.js
|----dev.js
screen:这个里面放置的是Screen类,主要的场景都可以写一个Screen类,Screen类上包含这个场景上的UI操作,比如登陆、后退、下拉刷新、下滑、绘制手势等。例如一个APP开始页面,包含关闭弹框,滑动窗口等功能。
import {swipe} from '../util/yiewdAction'; export default class StartScreen { constructor(driver, context) { this.driver = driver; this.context = context; } *closeAlert() { const driver = this.driver; const element = yield driver.elementByNameIfExists('closeActivity'); if (element) { yield element.click(); } yield driver.sleep(3000); } *slideScreen() { const driver = this.driver; yield swipe(driver, 300, 300, -300, 0, 500); yield driver.sleep(500); yield swipe(driver, 300, 300, -300, 0, 500); yield driver.sleep(500); yield swipe(driver, 300, 300, -300, 0, 500); } *openApp() { yield this.driver.waitForElementByClassName('Button', 3000, 100).click(); yield this.driver.sleep(5000); } }
cases:有了Screen类,我们只需要关心测试用例的编写了,从开启APP到进入待测页面,可以用Screen类的UI操作,不需要重复编写,例如:
import '../util/should'; import InitScreen from '../screen/InitScreen'; import StartScreen from '../screen/StartScreen'; import LoginScreen from '../screen/LoginScreen'; import MainScreen from '../screen/MainScreen'; import HomeIndexScreen from '../screen/HomeIndexScreen'; import HomeProductFixedScreen from '../screen/HomeProductFixedScreen'; import {env, nativeContext} from '../caps'; export default function freeList(driver, done) { const initScreen = new InitScreen(driver, nativeContext); const startScreen = new StartScreen(driver, nativeContext); const loginScreen = new LoginScreen(driver, nativeContext); const mainScreen = new MainScreen(driver, nativeContext); return driver.run(function *() { yield *initScreen.acceptAlert(); yield *initScreen.chooseEnv(env); yield *startScreen.closeAlert(); yield *startScreen.slideScreen(); yield *startScreen.openApp(); yield *mainScreen.closeActivity(); let contexts = yield driver.contexts(); const homeIndexScreen = new HomeIndexScreen(driver, contexts[contexts.length - 1]); yield *homeIndexScreen.goLogin(); yield *loginScreen.login(); yield *loginScreen.drawGesture(); yield *mainScreen.goLiCai(); //... done(); }); }
不需要重复写一些操作,进入到待测页面有Screen类提供的一条龙服务。
改造下来,代码看着舒服多了,而且没有用例这次通过,下次挂的情况。

本作品采用 知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议进行许可。