原文:http://www.cnblogs.com/hyddd/p/5593479.html。最近杂事比较多,原计划端午发的文章拖到昨天才写完。

Macaca-iOS 入门那些事 2

一. 前言

上文《Macaca-iOS 入门那些事》讲到 Macaca 环境部署及运行了第一个案例,本文将讲解其案例编写。

二. 测试案例解析

iOS 案例:macaca-mobile-sample.test.js,由 2 部分组成:

  1. 配置
  2. 测试案例

以上代码兼顾了 Android,所以会有冗余,简化如下:

1. 配置

var iOSOpts = {
    platformName: 'iOS',
    platformVersion: '9.3',         
    deviceName: 'iPhone 5s',
    app: '/Users/chenximing/workspace/ios/macaca-test2/macaca-test-sample/app/ios-app-bootstrap.zip'
};
/*
    platformName:平台名称
    platformVersioniOS系统版本,框架好像没用到这个参数,所以这玩意不重要
    deviceName:设备名称
    app:被测app路径
*/

2. 测试案例

var wd = require('webdriver-client')(iOSOpts);
describe('macaca mobile sample', function() {
    this.timeout(5 * 60 * 1000);
    var driver = wd.initPromiseChain();
    driver.configureHttp({
        timeout: 600000
    });

    before(function() {
        return driver
            .initDriver();
    });

    after(function() {
        return driver
            .sleep(1000)
            .quit();
    });

    it('#1 should login success', function() {
        return driver
            .login('12345678', '111111')
            .sleep(1000);
    });

...

});

这里可以细分为:

(1). driver 初始化
var wd = require('webdriver-client')(iOSOpts);
......
var driver = wd.initPromiseChain();
driver.configureHttp({
    timeout: 600000
});

webdriver-client 是什么?

上篇说到 macaca 是 c-s 模式的测试框架,client 负责被案例端调用的 API,server 负责调起 instruments 以及控制其执行测试。webdriver-client 就是上面说到的 client 端,提供控制操作的 API,《Macaca 的 API 文档》

(2). 测试框架
describe('macaca mobile sample', function() {
    this.timeout(5 * 60 * 1000);

    ......

    before(function() {
        return driver
            .initDriver();
    });

    after(function() {
        return driver
            .sleep(1000)
            .quit();
    });

    it('#1 should login success', function() {
        return driver
            .login('12345678', '111111')
            .sleep(1000);
    });

    ...

});

在这里,Macaca 使用一个第三方的测试框架 Mocha,macaca-cli 在 run 的时候加载该框架。

describe、before、after、it 等关键字均为 Mocha 提供,和传统 XUnit 框架功能类似(Mocha 默认是 BDD 模式,而 XUnit 是 TDD 模式),想了解更多,见Mocha 主页

(3). 测试案例
...

it('#1 should login success', function() {
    return driver
        .login('12345678', '111111')
        .sleep(1000);
    });

...

it 部分就是测试案例。

三. 进阶

1. BDD(Behavior-driven development)

为什么我会介绍 BDD? 因为 Mocha 就基于 BDD 思想的测试框架,并且我估计会有人把 BDD链式调用 的概念搞混。

BDD(Behavior Driven Development:行为驱动开发),是基于 TDD 发展的一种解决问题的思想,通过用类似自然语言方式描述软件行为,以达到可读性更高(让非技术人员也可以看懂)。

以上测试代码中,属于 BDD 部分由 Mocha 提供的,如:describe, it, before, after...这些均为 BDD 风格的接口。如果是 TDD 风格(如:XUnit)的接口则是:suite, test, setup, teardown...

2. 链式调用

(1)什么是链式调用
driver
  .native()
  .elementByName('PERSONAL')
  .click()
  .sleep(1000)
  .takeScreenshot()
  .elementByName('Logout')
  .click()
  .sleep(1000)
  .takeScreenshot();

以上代码组织方式为:链式调用。

如果你之前把BDD链式调用搞混,估计看过以下代码:

When(...).Then(...).And(...).Should(...)

这段代码就是 BDD 接口以链式方式调用,可读性非常高!但关于 BDD 的部分其实还是:When、Then、And、Should...

(2)为何 Macaca 测试案例使用链式调用风格?

某些情况下,使用链式调用方式书写代码是很舒服的,如 C# 的 linq:

var rs = user.Where(x => x.Length == 3).Select(x => x).ToList(); 

但如果把所有测试操作(无论操作间有无关联)都用链式调用方式组合,就比较奇怪了。如:

return driver
   .webview()
   .elementById('pushView')
   .tap()
   .sleep(5000)
   .webview()
   .elementById('popView')
   .tap()
   .sleep(5000)
   .takeScreenshot();

上面 2 个 webview element 的操作是没有任何关系的。而使用链式调用的场景一般是前后依赖、连续操作、层级递进,如上面的 linq 例子:where 的结果集,接着要进行数据提取,然后是再把集合封装为 list 结构。

所以,基于链式调用的原意,上面的案例的写法就有些奇怪了,并且 Node.js 的新手也不习惯。然而,为啥作者会写出这种的测试代码?原因在于:Node.js 这个语言!

Node.js 是异步编程语言,例子如下:

var el = driver.webview().elementById('hyddd')
el.tap()

上面 2 句,同步编程语言是怎么理解呢?

(1)获取 hyddd 的 element;

(2)对 element 进行 tap() 操作;

但换作异步编程语言呢?

(1)获取 hyddd 的 element;

(2)el.tap() 同时于 (1) 执行,也就说,el 还没赋值,(2) 就已经开始执行了,完全没等 (1) 返回 (2) 就执行了;

没法好好玩耍了,如果原生 Node.js 程序时要处理同步场景,就会出现所谓的callback hell,为了避免 callback hell,就出现了Promise 模式。嗯,在上面的测试代码中是不是看到这个单词?它作用就是把异步模式变为同步模式,同时避免 callback hell。而它的表现就是现在这种链式调用!!! 所以测试案例长得比较奇怪是开发语言导致的。

就个人的测试哲学而言,脚本性的语言是最适合写测试脚本的,但 Node.js 异步编程风格比较特别,增加了测试案例编写者入门门槛,所以我其实更倾向 Python。前几天和 Macaca 作者聊过,对 Python 的支持估计也要等一段时间,希望这天尽快到来。


↙↙↙阅读原文可查看相关链接,并与作者交流