Macaca-iOS入門那些事2
一. 前言
上文《Macaca-iOS入門那些事》講到Macaca環境部署及運行了第一個案例,本文將講解其案例編寫。
二. 測試案例解析
iOS案例:macaca-mobile-sample.test.js,由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:平台名稱
platformVersion:iOS系統版本,框架好像沒用到這個參數,所以這玩意不重要
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的支持估計也要等一段時間,希望這天盡快到來。