千里之行
始于足下

绘枫和畅

千里之行,始于足下

Wed.

木曜日

前段时间用的UI自动化测试框架主要是两个:Macaca和Appium。后来基于了非常多的原因,还是用了大家都用的Appium(这家伙对iOS10支持非常不好)。如果你刚接触这两个包装着Mocha的测试框架,而且想用Node去写整个测试框架,都会发现它们共同的毛病:慢,卡,不稳定,代码不方便阅读等等。这些是很多原因造成的,比如之前用Macaca写登录脚本是一长串Promise。

macaca代码示范

测试用例写出来后,在模拟器上跑着还不稳定,上一次用例通过了,这一次用例失败了,加上测试速度,格外让人蛋疼。后来经过大神指点迷津,在书写方式和架构上面进行了修改,整个项目看起来清爽不少。

翻新后的代码

一番改造后,抛弃了Promise,使用Generatoryield,最后的要点就是人们常说的“高耦合,低内聚”。

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类提供的一条龙服务。

改造下来,代码看着舒服多了,而且没有用例这次通过,下次挂的情况。

Master之令咒:

带我飞

©2016-2018 Powerd by Alchemy's Spruche 鄂ICP备14020745号