[TOC]
# 持續集成和前端自動化測試
? 持續集成是互聯網軟件開發上線流程中的核心一環,自動化測試是持續集成得以實現的核心步驟,缺乏了自動化測試,持續集成自然無從談起。
? 在日常的開發中,前端錯綜復雜的變化引發的 bug 往往令開發者頭疼,或多或少經歷過 修完東墻西墻倒 的經歷,此時前端自動化測試就顯得非常重要。
? 前端的自動化測試無非也是編寫測試用例,在持續集成時執行跑通全部測試用例。如果是一個短平快的小項目,引入前端自動化測試,編寫測試用例,無疑只會增加開發成本,然而當項目擴大、迭代頻繁、邏輯復雜、需求反復變更的情況下,回歸測試的成本是巨額的,自動化測試的優勢就能體現出來。
> 自動化測試的收益 = 迭代次數 \* 全手動執行成本 - 首次自動化成本 - 維護次數 \* 維護成本
? 盡早引入前端自動化測試不僅能夠減少項目 bug 出現概率 (尤其是回歸測試中的 bug),還能更好地進行代碼組織,增強項目的可維護性,尤其對于工程質量較差的項目,收益是巨大的;如果將其應用于持續集成中,commit 觸發自動執行測試腳本,還能大幅提升團隊的開發效率。
# 自動化測試的必要性
好處很多,包括減少錯誤、提高效率等,尤其是前端項目越來越龐大且多人維護時,前端自動化測試就會顯得尤其重要。
代價也有,畢竟需要額外的學習成本。但在你的項目中加入測試,也許沒你想象的那么困難。
# [JavaScript 測試︰ 單元 vs 功能 vs 集成測試](http://wildflame.me/javascript-testing-unit-functional-integration/)
大多數應用程序都需要 單元測試 和 功能測試,而許多復雜的應用程序在此基礎上,還需要 集成測試。
1. **單元測試** 測試單個函數或者類,提供輸入,確保輸出和預期的一樣。單元測試的粒度要盡可能小,不要考慮其他類和模塊的實現。用來確保每個組件正常工作 —— 測試組件的 API 。在面向對象的語言中,單元可以從單一方法到整個類。
2. **集成測試** 測試整個流程或者某組件能夠按預期的運行,用來覆蓋跨模塊的過程。同時也要包括一些反面用例,用來確保不同組件互相合作 —— 測試組件的 API, UI, 或者邊緣情況(比如數據庫I/O,登陸等等)。
3. **功能測試** 站在產品的角度測試各個場景,通過操作瀏覽器或者網站,忽略內部實現細節和結構,確保和預期的行為一樣。—— UI 界面功能測試
你應該把 單元,集成 和 功能測試 互相隔離開來,這樣你就可以在開發時分別的運行它們。在持續的集成過程中,測試一般會出現在下面三個階段。
1. 開發階段,主要是程序員反饋。這時單元測試很有用。
2. 中間階段,主要是能夠在發現問題時立刻停下來。這時各種測試都很有用。
3. 生產環境,主要是運行功能測試套件中一個叫做「冒煙測試」的子集,確保部署的時候沒有弄壞什么東西。
如果你問我該使用那個測試?**所有的**。
**在前端測試金字塔中,大部分測試都是單元測試。**
# BDD vs TDD
主流的測試類型,如何選擇測試的策略。
## TDD (Test-Driven Development) 測試驅動開發
? TDD 顧名思義,開發者根據需求先編寫測試用例,再逐步開發,最終滿足全部測試用例的需求。
? TDD 的基本思路就是通過測試來推動整個開發的進行,但測試驅動開發并不只是單純的測試工作,而是把需求分析,設計,質量控制量化的過程。
? TDD 的重要目的不僅僅是測試軟件,測試工作保證代碼質量僅僅是其中一部分,而且是在開發過程中幫助客戶和程序員去除模棱兩可的需求。TDD 首先考慮使用需求(對象、功能、過程、接口等),主要是編寫測試用例框架對功能的過程和接口進行設計,而測試框架可以持續進行驗證。
? 剛開始的時候,只有測試用例,未進行功能開發,執行測試用例,滿屏是紅色的測試用例不通過提示,隨著測試用例被滿足變綠,最終全部變綠,功能開發完成,因此前端自動化測試也被叫做 Red-Green Development。
> TDD 先寫測試再寫代碼,單位是模塊,多用于 單元測試
> 重點在測試代碼,屬于 白盒測試
> 測試內容是模塊,速度快,但是忽略模塊間依賴,安全感低
>
> ? 流程
> 1. 編寫測試用例
> 2. 運行測試,測試用例無法通過測試
> 3. 編寫代碼,時測試用例通過測試
> 4. 優化代碼,完成開發
> 5. 重復上述步驟
>
> ? 優勢
> 1. 長期減少回歸 bug
> 2. 代碼質量更好(組織,可維護性)
> 3. 測試覆蓋率高
> 4. 錯誤測試代碼不容易出現
## BDD (Behavior Driven Development) 行為驅動開發
? 測試用例模擬用戶的操作行為,通常在完成業務代碼開發之后,以用戶的操作為指導編寫測試代碼。當測試用例跑通之后,就可以認為系統的整體流程已經流暢。
BDD 的模式適用于平時的業務代碼開發,因為業務的需求有可能變更頻繁,但操作流程有可能不會變化,當業務代碼發生變化的時候,可以使用原來的測試用例繼續跑代碼,節省了開發時間。
BDD 先寫代碼再寫測試,測試單位是功能,多用于集成測試
重點在測試 UI(DOM)功能,屬于黑盒測試
測試內容是整套操作流程,速度慢,往往需要多個模塊配合,安全感高
> TDD 開發模式更適用于開發,類似方法函數庫,對于數據的處理,對于這種顯示組件,更加推薦于 BDD 的開發方式,這樣既有了測試,也不會增加過多的工作負擔,
>
> 在平時的項目中,通常使用 TDD 和 BDD 相結合來進行測試,TDD 負責方法類、獨立組件的測試。BDD 則負責整體業務模塊的測試。
一般的 TDD 的開發流程為:
1. 編寫測試 (一個會失敗的 case)
2. 運行測試,并看到這個測試失敗
3. 編寫代碼 (足夠讓測試通過的代碼)
4. 運行測試,并看到測試通過
5. 重構
6. 運行測試,并看到測試通過
然后**如此循環**,而在前端開發中,很長一段時間,這個流程受限于開發環境,比如添加了一個新的 JavaScript 源文件,開發者需要在 HTML 中引入相應地文件,以及響應的測試文件,然后刷新頁面 (有時候還需要清空瀏覽器緩存)。
在這個過程中,開發者真正關注的就是編寫測試,運行測試,編寫實現,重構等等,需要不斷的重復這個過程。而不是關注如刷新頁面,清空緩存,修改 HTML 對腳本的引用等武館的工作。
參考:
* [前端自動化測試jest_萌萌噠的瑞萌萌的博客](https://blog.csdn.net/weixin_46232841/article/details/117528453)
* [TDD 與 BDD 僅僅是語言描述上的區別么? - 知乎](https://www.zhihu.com/question/20161970)
* [從Unit Test到TDD再到BDD](https://www.jianshu.com/p/07f5ea4761ad)
* [虛擬座談會:代碼測試比率、測試驅動開發及行為驅動開發](http://www.infoq.com/cn/articles/virtual-panel-tdd-bdd)
## 斷言庫 Chai
斷言庫(assertion library)是用來寫斷言的庫。
維基百科的 [斷言(程序)](https://zh.wikipedia.org/wiki/%E6%96%B7%E8%A8%80_(%E7%A8%8B%E5%BC%8F))一文是這么解釋斷言的:在[程序設計](https://zh.wikipedia.org/wiki/%E7%A8%8B%E5%BC%8F%E8%A8%AD%E8%A8%88)中,**斷言**(**assertion**)是一種放在程序中的[一階邏輯](https://zh.wikipedia.org/wiki/%E4%B8%80%E9%9A%8E%E9%82%8F%E8%BC%AF)(如一個結果為真或是假的邏輯判斷式),目的是為了標示與驗證程序開發者預期的結果-當程序運行到斷言的位置時,對應的斷言應該為真。若斷言不為真時,程序會中止運行,并給出錯誤消息。
根據風格,斷言庫又區分為 TDD 風格 和 BDD 風格。[Chai](http://chaijs.com/) 便是其中一個著名的代表,它同時支持這兩種風格。
# 前端測試金字塔
前端測試金字塔是一個前端測試套件應該如何構建的結構化表示。
理想的測試套件由單元測試,一些快照測試和一些端到端(e2e)測試組成。

這是測試金字塔的改進版本,特定于測試前端應用程序。
# 前端測試框架
在大型項目或迭代頻繁的項目中,單元測試還是很必要的,當前單元測試框架很多,功能各不相同。使用測試框架的好處是可以讓我們寫測試更方便,比如有測試結果報告,還有一些 helper function 來幫助我們更好的編寫和組織測試代碼,比如`expect(counter.number).to.be.equal(0)`就是測試框架提供的很容易理解的代碼。

## Jest
https://jestjs.io/zh-Hans/
* facebook 靠山
* 基于 Jasmine 至今已經做了大量修改添加了很多特性
* 開箱即用配置少,API 簡單
* 支持斷言和仿真
* 支持快照(snapshot)測試
* 在隔離環境下測試
* 互動模式選擇要測試的模塊
* 優雅的測試覆蓋率報告,基于 Istanbul
* 較新,社區不十分成熟
* 全局環境,比如 describe 不需要引入直接用
* 較多用于 React 項目(但廣泛支持各種項目)
> [Why Do JavaScript Test Frameworks Use describe() and beforeEach()?](https://www.bignerdranch.com/blog/why-do-javascript-test-frameworks-use-describe-and-beforeeach/)
> [Testing JavaScript with Jest](https://flaviocopes.com/jest/#run-jest-with-vs-code)
> https://www.valentinog.com/blog/jest/
## Mocha
[Mocha](https://mochajs.org/) 是一個功能豐富的 JavaScript 測試框架,運行在 Node.js 和瀏覽器上,使得異步測試簡單而有趣。Mocha 測試是串行運行的,允許靈活和準確的報告,同時將未捕獲的異常映射到正確的測試用例。
默認會自動運行當前項目的 `test` 文件夾下的測試文件。
* 靈活(不包括斷言和仿真,自己選對應工具)
流行斷言庫可選擇:[chai](https://www.chaijs.com/api/assert/),[sinon](https://ssh://github.com/sinonjs/sinon)
* 社區成熟用的人多,測試各種東西社區都有示例
* 需要較多配置
* 可以使用快照測試,但依然需要額外配置
> [Unit testing Node.js applications using Mocha, Chai, and Sinon](https://blog.logrocket.com/unit-testing-node-js-applications-using-mocha-chai-and-sinon/)
## Jasmine
[Jasmine](https://jasmine.github.io/index.html) 是一個針對 JavaScript 的行為驅動開發的測試框架,不依賴于任何其他的 JavaScript 框架或者文檔對象模型(DOM),最新版本改進了對 Node.js 的支持,同時還做了一些提升內部質量的工作。
* 開箱即用(支持斷言和仿真)
* 只支持 BDD
* 全局環境
* 不依賴于任何其它的 JavaScript 框架
* 不需要 DOM
* 結構簡單
* 可以運行在 Node.JS 或者 Html 中
* 基于行為驅動開發 Jasmine
## AVA
未來的測試運行器。
從 Mocha 切換到 AVA 讓測試時間從 31 秒下降到 11 秒。測試并發執行強制你寫原子測試,意味著測試不需要依賴全局狀態或者其他測試的狀態,這是一件非常好的事情。
[avajs/zh_CN/readme.md](https://github.com/avajs/ava-docs/blob/master/zh_CN/readme.md)
## Karma
[Karma](https://karma-runner.github.io/) 是一個基于 Node.js 的 JavaScript 測試執行過程管理工具(Test Runner)。由 Google 團隊開發的一套前端測試運行框架。它不同于測試框架(例如 jasmine,mocha 等),該工具可用于測試所有主流 Web 瀏覽器,也可以集成到 CI(Continuous integration)工具,還可以和其他代碼編輯器一起使用。
Karma 會監控配置文件中所指定的每一個文件,每當文件發生改變,它都會向測試服務器發送信號,來通知所有的瀏覽器再次運行測試代碼。此時,瀏覽器會重新加載源文件,并執行測試代碼。其結果會傳遞回服務器,并以某種形式顯示給開發者。
訪問瀏覽器執行結果,可通過以下的方式:
* 手工方式 - 通過瀏覽器,訪問 URL 地址 - http://localhost:9876/
* 自動方式 - 讓 karma 來啟動對應的瀏覽器
主要完成以下工作:
1. Karma 啟動一個 web 服務器,生成包含 js 源代碼和 js 測試腳本的頁面;
2. 運行瀏覽器加載頁面,并顯示測試的結果;
3. 如果開啟檢測,則當文件有修改時,執行繼續執行以上過程。
## 其他
如果想要對前端產品進行測試,還需要另外一個工具:
* 測試瀏覽器 -- [Puppeteer](Puppeteer%E5%AD%A6%E4%B9%A0.md)
# 前端e2e測試
單元測試
·業務驅動開發 & 測試驅動開發
·黑盒測試和白盒測試
·測試覆蓋率
·前端項目的單測集成
·Node項目的單測集成
e2e測試
·前端e2e測試
## 附錄
http://www.daqianduan.com/1845.html
前端測試工具集錦 https://qaseven.github.io/2016/05/24/front-end-tools/
https://www.douban.com/note/509058712/
[前端自動化測試](https://www.baidu.com/s?wd=%E5%89%8D%E7%AB%AF%E8%87%AA%E5%8A%A8%E5%8C%96%E6%B5%8B%E8%AF%95)
[如何進行前端自動化測試?](https://www.zhihu.com/question/29922082)
[聊聊前端開發的測試](https://zhuanlan.zhihu.com/p/26050231)
# 用 Headless Chrome 代替 Phantomjs。
1. 我爸是 Google ,那么就意味不會出現 Phantomjs 近 2k 問題沒人維護的尷尬局面。 比 Phantomjs 有更快更好的性能。
2. 有人已經做過實驗,同一任務,Headless Chrome 要比現 Phantomjs 更加快速的完成任務,且占用內存更少
3. chrome 對 ECMAScript 2017 (ES8) 支持,同樣 headless 隨著 chrome 更新,意味著我們也可以使用最新的 js 語法來編寫的腳本,例如`async`,`await`等。
4. 完全真實的瀏覽器操作,chrome headless支持所有chrome特性。
5. 更加便利的調試,我們只需要在命令行中加入 `--remote-debugging-port=9222`,再打開瀏覽器輸入 `localhost:9222` (ip為實際運行命令的ip地址)就能進入調試界面。
Google 最近放出了終極大招—— [Puppeteer 學習](Puppeteer%E5%AD%A6%E4%B9%A0.md)
***
# chrome 跨域調試
跨域設置
~~~
--disable-web-security
~~~
1. Chrome 桌面快捷方式=》鼠標右鍵=》屬性-》目標后。
2. MyChrome -》高級-》啟動參數
`Allow-Control-Allow-Origin:*` [跨域插件](https://chrome.google.com/webstore/detail/allow-control-allow-origi/nlfbmbojpeacfghkpbjhddihlkkiljbi)
# 單元測試工具
[Mocha](https://mochajs.org/)
[k6](https://k6.io/)
單元測試工具 —— [karma](http://karma-runner.github.io/latest/index.html)(跑測試用例的容器)
[jasmine](https://jasmine.github.io/) —— 編寫測試用例。
[macaca](https://github.com/alibaba/macaca) —— 多端自動化測試解決方案
# 參考
[測試網](http://www.51testing.com/html/96/category-catid-96.html)
[你需要了解的前端測試“金字塔”](http://web.jobbole.com/93120/)
[測試你的前端代碼 – part1(介紹篇)](http://web.jobbole.com/91123/)
- 講解 Markdown
- 示例
- SVN
- Git筆記
- github 相關
- DESIGNER'S GUIDE TO DPI
- JS 模塊化
- CommonJS、AMD、CMD、UMD、ES6
- AMD
- RequrieJS
- r.js
- 模塊化打包
- 學習Chrome DevTools
- chrome://inspect
- Chrome DevTools 之 Elements
- Chrome DevTools 之 Console
- Chrome DevTools 之 Sources
- Chrome DevTools 之 Network
- Chrome DevTools 之 Memory
- Chrome DevTools 之 Performance
- Chrome DevTools 之 Resources
- Chrome DevTools 之 Security
- Chrome DevTools 之 Audits
- 技巧
- Node.js
- 基礎知識
- package.json 詳解
- corepack
- npm
- yarn
- pnpm
- yalc
- 庫處理
- Babel
- 相關庫
- 轉譯基礎
- 插件
- AST
- Rollup
- 基礎
- 插件
- Webpack
- 詳解配置
- 實現 loader
- webpack 進階
- plugin 用法
- 輔助工具
- 解答疑惑
- 開發工具集合
- 花樣百出的打包工具
- 紛雜的構建系統
- monorepo
- 前端工作流
- 爬蟲
- 測試篇
- 綜合
- Jest
- playwright
- Puppeteer
- cypress
- webdriverIO
- TestCafe
- 其他
- 工程開發
- gulp篇
- Building With Gulp
- Sass篇
- PostCSS篇
- combo服務
- 編碼規范檢查
- 前端優化
- 優化策略
- 高性能HTML5
- 瀏覽器端性能
- 前后端分離篇
- 分離部署
- API 文檔框架
- 項目開發環境
- 基于 JWT 的 Token 認證
- 扯皮時間
- 持續集成及后續服務
- 靜態服務器搭建
- mock與調試
- browserslist
- Project Starter
- Docker
- 文檔網站生成
- ddd