Karma+Jasmine+istanbul+webpack自動化單元測試
前言
一直用别人配置好的東西,經常看别人寫教程來寫簡單的單元測試,閑來無事自己也來撸個配置玩玩。說幹就幹,從開始到運作成功差不多5個小時。遇到各種問題,主要是各種子產品的配置版本問題。
簡單介紹一下要用到東西是什麼
Karma的介紹
Karma是Testacular的新名字,在2012年google開源了Testacular,2013年Testacular改名為Karma。Karma是一個讓人感到非常神秘的名字,表示佛教中的緣分,因果報應,比Cassandra這種名字更讓人猜不透!
Karma是一個基于Node.js的JavaScript測試執行過程管理工具(Test Runner)。該工具可用于測試所有主流Web浏覽器,也可內建到CI(Continuous integration)工具,也可和其他代碼編輯器一起使用。這個測試工具的一個強大特性就是,它可以監控(Watch)檔案的變化,然後自行執行,通過console.log顯示測試結果。
Jasmine的介紹
Jasmine是單元測試架構,我将用Karma讓Jasmine測試自動化完成。jasmine提出行為驅動【BDD(Behavior Driven Development)】,測試先行理念,Jasmine的官網
istanbul的介紹
istanbul是一個單元測試代碼覆寫率檢查工具,可以很直覺地告訴我們,單元測試對代碼的控制程度。(ps:這個玩意浪費我好久時間,後面詳細說怎麼配置)
webpack的介紹
webpack 是一個現代 JavaScript 應用程式的子產品打包器(module bundler)。當 webpack 處理應用程式時,它會遞歸地建構一個依賴關系圖(dependency graph),其中包含應用程式需要的每個子產品,然後将所有這些子產品打包成少量的 bundle - 通常隻有一個,由浏覽器加載。(引用webpack中文網介紹)
建構Test工程,開始新生上路
- 建立一個檔案test-demo
- 進入test-demo,在目前檔案夾裡打開指令行,輸入
;npm init -y
- 自動生成package.json檔案。
ps: 我的環境:nodejs v8.2.1 npm v5.3.0
安裝相關依賴
安裝Karma
npm install karma -g
并且還有安裝項目中使用
需要全局安裝,可以使用指令行。
安裝完成以後,指令行輸入
karma start
在浏覽器輸入
http://localhost:9876/
如果出現以上資訊,表示
karma
已經安裝成功。
Karma配置
初始化karma配置檔案karma.conf.js
ctrl+c 結束剛才啟動的Karma
在指令行輸入
karma init
接下就是一段詢問關于配置的問題。(ps:karma.conf.js配置可以自己修改,這裡是快速生成配置)
1. Which testing framework do you want to use ?(你想要使用哪個測試架構?)
預設是jasmine。(如果你想用其他可以自己修改),直接回車下一步
-
Do you want to use Require.js ? (你要使用Require.js嗎?)
This will add Require.js plugin. (這将添加Require.js插件。)
Press tab to list possible options. Enter to move to the next question. (按頁籤列出可能的選項。 輸入轉到下一個問題。)
預設是no。(現在都在使用webpack打包,這也是為什麼你肯定奇怪的地方,單元測試為什麼要用webpack) ,直接回車下一步
-
Do you want to capture any browsers automatically ? (你想要在哪些浏覽器裡面運作)
Press tab to list possible options. Enter empty string to move to the next question.(和上面一樣)
預設是Chrome。(你可以添加更多浏覽器回車就是填寫下一個浏覽器名稱,必須是你電腦安裝的浏覽器,最好還是去karma.conf.js添加直覺一些),直接按2次回車下一步
-
What is the location of your source and test files ?(測試檔案的位置是什麼?)
You can use glob patterns, eg. “js/.js” or “test/*.spec.js,就是說scr檔案夾下的所有
字尾都是t測試用例檔案。回車下一步 你寫了這樣一定會跟我報錯, 需要去如圖建立随意.spec.js
字尾檔案,.spec.js
如果不想建,可以直接下一步,等會到
karma.conf.js
修改。
-
Should any of the files included by the previous patterns be excluded ?(是否應排除某些包含的任何檔案?)
You can use glob patterns, eg. “/.swp”. (您可以使用glob模式,例如。“/.SWP”。)
這是為了性能優化,排除那些檔案不需要去監聽,加快運作速度。如果你不确定要排除哪些檔案,可以去
修改。我就直接直接下一步了。karma.conf.js
-
Do you want Karma to watch all the files and run the tests on change ? (你想要Karma來監聽所有的檔案,并在變化中運作測試嗎?)
Press tab to list possible options. (按頁籤列出可能的選項。)
預設yes,它的意思你寫完了
字尾檔案會自動運作測試,等我們把.spec.js
Karma
跑起來,在自動運作。
這裡no。
這就生成出來了配置
找一款你順手的編輯器打開它,(我的用vscode)
一大堆看不懂的東西,我給它們一一注釋一下;
接下來就說關于依賴插件plugins
1. 需要可以打開Chrome浏覽器的插件
npm install karma-chrome-launcher --save-dev
2. 需要可以運作jasmine的插件
npm install karma-jasmine --save-dev
3. 需要可以運作webpack的插件
npm install karma-webpack --save-dev
4. 需要可以顯示sourcemap的插件
npm install karma-sourcemap-loader --save-dev
5. 需要可以顯示測試代碼覆寫率的插件
npm install karma-coverage-istanbul-reporter --save-dev
插件就先安裝這麼多,後面需要在安裝,可以這樣一起安裝:
把插件寫到配置裡面去
我們先隻需要前2個,後面注釋起來,讓
karma
能随時跑起來。
然後去
package.json
配置一個npm指令,編輯器或者ide可以直接運作npm指令。
我們
karma
可以運作起來,karma配置先就到這裡。
安裝Jasmine
并且還有安裝項目中使用
在安裝的過程我們可以去看看jasmine文檔
jasmine 5個核心
- describe塊稱為”測試套件”(test suite),表示一組相關的測試。它是一個函數,第一個參數是測試套件的名稱(”index.js的測試”),第二個參數是一個實際執行的函數。
- it塊稱為”測試用例”(test case),表示一個單獨的測試,是測試的最小機關。它也是一個函數,第一個參數是測試用例的名稱(”1應該是數字”),第二個參數是一個實際執行的函數。
- expect是解析一段代碼,傳回解析後的值。
- 比對器,jasmine内置了很多比對器,例如:toBe 、not.toBe等,也可以自定義比對器。
- 鈎子函數,為了減少重複性的代碼,jasmine提供了beforeEach、afterEach、beforeAll、afterAll方法。
- beforeEach() :在describe函數中每個Spec執行之前執行;
- afterEach() :在describe函數中每個Spec執行之後執行;
- beforeAll() :在describe函數中所有的Specs執行之前執行,且隻執行一次
- afterAll () : 在describe函數中所有的Specs執行之後執行,且隻執行一次
看了文檔我們去寫一個簡單測試用例。
這個例子非常簡單,
1+1===2
;
因為我們的測試示例寫的是對的,是以沒有任何錯誤提示。
怎麼看運作結果,karma會自動打開一個谷歌浏覽器
點選後一片空白
打開控制台(F12)
可以看到輸出結果。非常ok
接下來我們加一個1+1===3,這個按正常來說是錯的,
你會發現沒有任何提示,因為我們沒有安裝一些東西,後面來說。現在隻能去看karma打開的谷歌浏覽器的控制台了。
有一個錯誤提示,說預期2,和比對結果3不對應。ok沒毛病。
簡陋版測試已經跑起來了,接下來我們要寫自己代碼
add相加函數
。
安裝Webpack
注意:Webpack有3個版本,1,2,3每個版本某些寫法都有些差别,注意看官方文檔,最新版3.5.5。
安裝需要時間,這個我們去寫個簡單的例子,一個簡單的add函數。
這裡用的es6,子產品導出,浏覽器還不認識,需要用到babel轉換。
- babel核心檔案
npm install babel-core --save-dev
- webpack的Loader處理器
npm install babel-loader --save-dev
- babel的istanbul覆寫率插件
npm install babel-plugin-istanbul --save-dev
- babel轉換到哪個版本這裡是ES2015
插件就先安裝這麼多,後面需要在安裝,可以這樣一起安裝:npm install babel-preset-es2015 --save-dev
這時候我們代碼還是那樣,需要去配置
karma.conf.js
,
webpack配置就不多做介紹,這裡不是webpack教程,也不是一兩句可以說完,看教程。
因為這裡配置比較簡單,就直接放在裡面。如果複雜就需要單獨抽出去做一個配置檔案。
ps:它和我們一般項目的配置是有點差別的,webpack有四個核心概念:入口(entry)、輸出(output)、loader、插件(plugins)。這裡不需要入口(entry)和輸出(output)配置。這點需要注意。
還需要打開注釋的插件
運作一下
npm run unit
, 沒錯誤繼續。一步一個腳印,不要到最後全是錯誤,放棄了。邊寫邊測試。
測試add函數
- add.spec.js引入add.js
import add from './add';
- 新增一個測試套件
- 運作
npm run unit
- karma打開的浏覽器檢視
出問題了,現在浏覽器都還不識别
import
。我們需要用
babel
轉換成ES5顯示。
我們需要配置preprocessors
我們在運作,打開控制台檢視:
完美運作
接着繼續,我們還需要生成源檔案映射的map檔案,
修改配置:
注意:每次修改完都需要重新運作
karma.conf.js
。運作沒有問題,我們接着繼續最後一個話題
npm run unit
代碼覆寫率顯示。
istanbul
安裝Istanbul
還需要安裝Istanbul相關的依賴
1. webpack的Loader處理器
npm install istanbul-instrumenter-loader --save-dev
2. 測試覆寫率顯示插件
npm install karma-coverage-istanbul-reporter --save-dev
我們先安裝他們,然後去修改
karma.conf.js
先給
babel
加上插件
plugins: ['istanbul']
在寫上
istanbul-instrumenter-loader
的配置。
注意:這是webpack官方給的例子,注意畫紅線的,官方給的有問題,這個配置是決定Loader的優先級。
添加完成以後,重新運作
npm run unit
。沒問題繼續。
我們使用
coverage-istanbul
顯示測試結果
打開所有插件注釋。
覆寫率顯示配置,看注釋說明
注意:一定要打開自動監聽才有覆寫率顯示,
運作以後,就會生成
指令行顯示
檔案夾裡面顯示
怎麼測覆寫率(code coverage)
它有四個測量次元。
- 行覆寫率(line coverage):是否每一行都執行了?
- 函數覆寫率(function coverage):是否每個函數都調用了?
- 分支覆寫率(branch coverage):是否每個if代碼塊都執行了?
- 語句覆寫率(statement coverage):是否每個語句都執行了?
export default function add(num1, num2) {
return num1 + num2;
}
我們将這個函數變得複雜點,如果不寫num2,就預設是0。
export default function add(num1, num2) {
if (num2 === undefined) num2 = ;
return num1 + num2;
}
指令行顯示結果
浏覽器打開
coverage/html/index.html
注意:指令行顯示合計測試覆寫率,詳細需在浏覽器看。
測試結果分析:
1個語句覆寫率(statement coverage)沒有覆寫到,1個分支覆寫率(branch coverage)沒有覆寫到,1個函數覆寫率(function coverage)已經調用,3行行覆寫率(line coverage)全部覆寫
我們再來個複雜的栗子:
export default function add(num1, num2) {
if (num1 === undefined) num1 = ;
if (num2 === undefined) num2 = ;
return num1 + num2;
}
指令行顯示結果
浏覽器打開
coverage/html/index.html
測試結果分析:
2個語句覆寫率(statement coverage)沒有覆寫到,2個分支覆寫率(branch coverage)沒有覆寫到,1個函數覆寫率(function coverage)已經調用,3行行覆寫率(line coverage)全部覆寫
增加測試用例
全部覆寫,ok完工。demo