上文《Macaca-iOS入門那些事》講到Macaca環境部署及運行了第一個案例,本文將講解其案例編寫。html
iOS案例:macaca-mobile-sample.test.js,由2部分組成:ios
以上代碼兼顧了Android,因此會有冗餘,簡化以下:git
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路徑 */
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); }); ... });
這裏能夠細分爲:github
var wd = require('webdriver-client')(iOSOpts); ...... var driver = wd.initPromiseChain(); driver.configureHttp({ timeout: 600000 });
webdriver-client是什麼?web
上篇說到macaca是c-s模式的測試框架,client負責被案例端調用的API,server負責調起instruments以及控制其執行測試。webdriver-client就是上面說到的client端,提供控制操做的API,《Macaca的API文檔》。編程
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的時候加載該框架。bootstrap
describe、before、after、it等關鍵字均爲Mocha提供,和傳統XUnit框架功能相似(Mocha默認是BDD模式,而XUnit是TDD模式),想了解更多,見Mocha主頁。api
... it('#1 should login success', function() { return driver .login('12345678', '111111') .sleep(1000); }); ...
it部分就是測試案例。app
爲何我會介紹BDD? 由於Mocha就基於BDD思想的測試框架,而且我估計會有人把 BDD 和 鏈式調用 的概念搞混。框架
BDD(Behavior Driven Development:行爲驅動開發),是基於TDD發展的一種解決問題的思想,經過用相似天然語言方式描述軟件行爲,以達到可讀性更高(讓非技術人員也能夠看懂)。
以上測試代碼中,屬於BDD部分由Mocha提供的,如:describe, it, before, after...這些均爲BDD風格的接口。若是是TDD風格(如:XUnit)的接口則是:suite, test, setup, teardown...
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...
某些狀況下,使用鏈式調用方式書寫代碼是很舒服的,如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的支持估計也要等一段時間,但願這天儘快到來。