本文的目錄結構:css
前端自動化測試的方向有:html
單元測試已經有很是完善的工具體系,借用2016 JavaScript 之星的圖,經常使用的單元測試框架有:前端
UI迴歸測試一般採用的方法是像素對比:java
初次運行的時候,會截圖並做爲baseline,後面再運行的時候,再生成截圖,並與baseline比較,生成diff結果。react
像素對比須要注意的事項:git
以下圖,很方便的實現了一個百度貼吧自動發帖的功能。github
一般的工具備:chrome devtool,PageSpeed等在線測試網站。chrome
考慮到咱們主題是nek-ui組件庫的測試,性能測試的部分,這裏不作贅述。npm
咱們的測試對象是NEK-UI組件庫,這一部分分析了其餘組件庫的測試方法並選擇了最終的測試方案。編程
RegularUI使用的測試方案是karma + mocha的黃金搭檔
這種方式存在的問題:
Ant-design是螞蟻金服的一套企業級的 UI 設計語言和 React 實現,目前是Github上一個很火的項目:
Ant-design做爲一個基於react的組件庫,使用的測試框架是一樣出自Facebook的Jest。
Ant-design使用的是Jest中稱爲snapshot testing的測試方案。
Jest的官方文檔上介紹到,Jest的Snapshot Testing與典型的snapshot test不一樣,不是生成截圖並比較圖片的差別,而是直接輸出React tree 的最終渲染dom結構。
Snnpshot Testing介紹:
再來看看Ant-design中的實際使用:
測試某個組件的時候,就會引入改組件文件夾裏demo文件夾下的全部md文件,這個md文件是組件的各類示例,同時也用於ant-design的官方文檔。而後,使用enzyme和enzyme-to-json提供的方法通過render->renderToJson->toMatchSnapshot, 第一次運行的時候會輸出以下的.snap文件:
這個文件要隨着代碼一塊兒提交到倉庫,下次運行測試的時候,就和這個.snap文件作比較。
固然僅僅測試dom結構不變是不夠的,ant-design的測試裏,還有模擬用戶操做的測試。以下兩個文件,demo.test.js是上面的snapshot部分,index.test.js是模擬用戶操做部分。
Index.test.js裏作了什麼呢?
在組件上綁定事件方法,而後模擬事件,判斷方法是否被調用。
這種方式存在的問題:
分析完了2個組件庫的測試方案,那麼咱們指望的測試方案應該包含什麼呢?
能方便的管理test case。
基於此,咱們最終選擇了PhantomFlow。
PhantomFlow是基於決策樹(decision tree)的ui test 框架,是對PhantomJS、CasperJS、PhantomCSS的包裝。
PhantomFlow假定若是頁面正常,那麼在相同的操做下,每次頁面所展示的應該是同樣的。基於這點,使用者只須要定義一系列的操做流程和決策分支,而後利用PhantomCSS進行截圖和圖像對比。最後將測試結果在一個可視化報表中展示出來。
這裏採用倒序的方式先來看一下PhantomFlow生成的測試報告,再介紹具體的使用:
這是PhantomFlow的母公司Huddle在他們實際的業務中使用的報告截圖:
同時PhantomFlow也提供了單獨查看某一個操做流的功能:
圖中的每一條線表明一個用戶操做流。綠色的點表示截圖對比經過,紅色的點表示截圖對比失敗,灰色的點表示這僅僅是PhantomFlow流程中的一步,並無真正的操做。
黃色的表示是一個操做,可是操做裏面並無進行截圖。咱們只要關心其中綠色的點和紅色的點。
PhantomFlow是基於決策樹的,那麼什麼是決策數呢?不必吧它想的那麼神祕,咱們能夠認爲它就是普通的流程圖。
flow (string, callback):初始化一個test suite,回調函數中能夠包含step, chance 和 decision。
step (string, callback):一個單獨的步驟,回調函數中能夠包含PhantomCSS的截圖,CasperJs的操做事件和斷言
decision (object):定義一個用戶的決定,參數是一個對象,key用來描述decision的名稱,value是一個function,裏面能夠包含後續的decision, chance和step
chance (object):功能上同decision同樣,只是在語義上區分decision,用來描述不是用戶主動的行爲。
step對應決策樹中的矩形,表示用戶具體的某一個操做。decision和chance對應決策樹中的菱形,表示用戶的選擇。
這是用PhantomFlow描述用戶喝咖啡的一個場景:
PhantomFlow提供了簡單的方法來描述用戶的操做流,具體的操做使用回調函數裏的CasperJS來完成:
function goToPage() {
casper.thenOpen("http://localhost:9001/test/index.html", function() {
this.echo('PageTitle: ' + this.getTitle());
phantomCSS.turnOffAnimations();
});
}
function injectModule(json) {
casper.evaluate(function(json) {
console.log(JSON.stringify(json));
new NEKUI.UISelect(json).$inject('#module');
}, json);
casper.onConsoleMessage = function(msg) {
console.log(msg);
}
}
function goToModule() {
casper.waitForSelector(
'#module .u-select2',
function success() {
phantomCSS.screenshot('#module .u-select2');
casper.test.pass('Should see the uiselect module' );
},
function timeout() {
casper.test.fail('Should see the uiselect module');
}
)
}
function clickModule() {
casper.click('#module .dropdown_hd');
casper.waitForSelector(
'#module .dropdown_bd',
function success() {
phantomCSS.screenshot('body');
casper.test.pass('Should see the options of module');
},
function timeout() {
casper.test.fail('Should see the options of module');
}
)
}
function selectAnOption(optionIndex) {
casper.click('#module .m-listview li:nth-child(' + (optionIndex+1) + ')');
phantomCSS.screenshot('body');
}複製代碼
在npm test後帶上以下參數便可
report:打開瀏覽器,生成測試報告。
debug:輸出更多的log信息,強制切換到單線程運行。
earlyexit: 默認爲false,設置爲true的話,遇到第一個failure就會終止測試。
threads:設置多線程來運行測試,默認爲4。
casper.thenOpen(String location[, mixed options]): 用來打開一個地址,當網頁加載完成以後,執行一個方法。
casper.waitForSelector(String selector[, Function then, Function onTimeout, Number timeout]):等到DOM裏有一個元素匹配選擇器,能夠傳入成功的方法和失敗的方法,和等待的毫秒數(默認5000)。
casper.click(String selector, [Number|String X, Number|String Y]):在匹配選擇器的第一個元素上執行一次click
casper.mouseEvent(String type, String selector, [Number|String X, Number|String Y]):在匹配選擇器的第一個元素上觸發鼠標事件。支持的事件有:mouseup、mousedowm、click、dblclick、mousemove、mouseover、moustout、mouseenter、mouseleave and contextmenu
casper.getHTML([String selector, Boolean outer]):獲取匹配選擇器裏的元素的內容。
casper.evaluate(Function fn[, arg1[, arg2[, …]]]):在打開的當前頁面環境下執行方法。
casper.test.fail(String message):添加一個fail test。
casper.test.pass(String message):添加一個pass test。
casper.test.assertEquals(mixed testValue, mixed expected[, String message]):斷言兩個值嚴格相等。
持續集成(Continuous integration,CI),一種軟件工程流程,指工程師將本身對於軟件的複本,天天集成數次到主幹上。在測試驅動開發(TDD)的作法中,一般還會搭配自動單元測試。
Travis-ci是一款持續集成服務,它可以很好地與Github結合,每當代碼更新時自動地觸發集成過程。Travis CI
打開Travis CI的官網,用Github帳號登陸。
選擇須要打開Travis CI服務的倉庫:
開通了服務的倉庫,每當有push代碼的時候,Travis CI就會爲咱們執行相關的操做。這裏能夠查看運行的進度和結果等。
在Github提交記錄裏也會顯示CI運行的結果。
要告訴Tracvis執行什麼,須要在咱們的項目裏添加一個.travis.yml文件,其最簡單的配置以下:
這裏指定了CI運行的語言,語言版本,哪些分支,install執行npm install, script是具體的操做部分,這裏讓CI執行 npm test。
Travis CI在執行完以後,會將結果郵件通知給用戶, 默認規則以下:
By default, email notifications are sent to the committer and the commit author when they are members of the repository,
that is they have
- push or admin permissions for public repositories.
- pull, push or admin permissions for private repositories.
Emails are sent when, on the given branch:
- a build was just broken or still is broken.
- a previously broken build was just fixed.複製代碼
關於travis ci的生命週期等更多配置能夠查閱這裏
一樣的使用Github帳號登錄:
選擇開啓服務的倉庫:
在項目的package.json文件script裏添加一條coverage的命令, 即將istanbul等覆蓋率工具生成的lcov文件給coveralls:
在travis.yml文件的after_script中運行npm run coverage,告訴CI服務器執行這條命令:
自動化測試不只能有效的減小人工維護成本,同時爲代碼的維護迭代提供保障。
前端自動化測試的方向有:單元測試、UI迴歸測試、功能測試、性能測試。
RegularUI採用karma+mocha的單元測試,ant-design使用Jest的snapshot測試與模擬用戶的功能測試相結合的方式。
PhantomFlow是基於決策樹的,對PhantomJS, CasperJS, PhantomCSS的包裝。以簡單的方式描述用戶操做流。並配以CasperJS的頁面操做,PhantomCSS的截圖,達到很是好的自動化測試效果。
測試時要保證數據的肯定性和添加適當的斷言。
CI是一種好的軟件工程思想。Travis CI簡單易用,解放了開發人員手動運行測試,很是值得在項目中引入。