來,加入前端自動化單元測試
最近閑來無事,開始摸索前端單元測試。一是不備之需,二是確實在實際項目中能夠用到單元測試。這樣可以提高開發(fā)效率,提升代碼質(zhì)量,完全可以單獨對 JS 進(jìn)行測試,無需頁面,不依賴其他第三方。
為什么需要單元測試
在這里首先需要知道單元測試的目的及結(jié)果:
- 使代碼健壯,質(zhì)量高,兼容各種臨界點;
- 減少 QA 測試報告的反饋,提高自我影響力;
- 保證代碼的整潔清晰。
如果需要刨根問底追究為什么需要進(jìn)行單元測試,那我們可以開始講講實際項目開發(fā)中遇到的一些問題:
- QA 不斷反饋代碼有 BUG (此時你正在投入的開發(fā),然后被打擾...);
- 代碼出現(xiàn) BUG,疊加代碼修復(fù) BUG(代碼越來越難維護(hù)...);
- 已經(jīng)開發(fā)完成一個模塊,但是沒有頁面提供調(diào)試測試;
- 你開發(fā)完成的功能,每次都有許多細(xì)小的 BUG(個人影響力下降...)。
好了,列舉了這么多原因,相信你也開始心虛了,回去繼續(xù)搬磚檢查檢查代碼有沒有問題,如果你面色從容,大神,請手下我的膝蓋。
總結(jié):單元測試的目的只有一個,用來確定是否適合使用
如何進(jìn)行單元測試
如果明白了為什么要進(jìn)行單元測試,相信你已經(jīng)可以開始著手為自己的代碼寫一些單元測試代碼。測試從字面理解就是檢驗,看對象是否達(dá)標(biāo),達(dá)標(biāo)就是 pass,不達(dá)標(biāo)就是 fail。產(chǎn)品有這樣一個需求,如果結(jié)果是 3 達(dá)到目標(biāo)且返回的為有效的數(shù)字類型才可以進(jìn)行比較,下面看個栗子:
- /**
- * 獲取 a 除以 b 的結(jié)果
- * @param {[Number]} a [數(shù)字]
- * @param {[Number]} b [數(shù)字]
- * @return {[Number]} [結(jié)果數(shù)字]
- */
- function division(a, b) {
- return a / b;
- }
- // 測試代碼
- function test() {
- var result = division(6, 2);
- if (result === 3) {
- console.log('pass');
- } else {
- console.log('fail');
- }
- }
咋一看上面的代碼沒什么問題,可以滿足產(chǎn)品的需求,但是問題來了,如果 b 為 0,這個模塊就出現(xiàn)了 BUG,同時如果下次需要達(dá)到其他的值就算通過,那就得去修改測試代碼,這樣的測試代碼本身也太不健全。于是乎有了下面的方式:
- /**
- * 獲取 a 除以 b 的結(jié)果
- * @param {[Number]} a [數(shù)字]
- * @param {[Number]} b [數(shù)字]
- * @return {[Number]} [結(jié)果數(shù)字]
- */
- function division(a, b) {
- if (b === 0) {
- return 0;
- } else {
- return a / b;
- }
- }
- function test(name, result, expect) {
- if (result === expect) {
- console.log(name + '-> pass');
- } else {
- console.log(name + '-> fail');
- }
- }
- test('normal number', division(6, 2), 3);
- test('zero', division(6, 0), 0);
如果需要期望值為 10 就通過,那可以這樣:
- test('normal number is 10', division(20, 2), 10);
單元測試環(huán)境搭建及代碼示例
但是隨著前端迅速的發(fā)展,也出現(xiàn)了很多測試框架,下面我演示我在實際項目中使用的測試框架環(huán)境配置 karma + jasmine,對于 karma、jasmine 我就不介紹,網(wǎng)上一搜一大把介紹:
1. 安裝 node 環(huán)境
依賴于 node 作為基礎(chǔ)環(huán)境,安裝完成在控制臺運(yùn)行下面命令查看是否安裝成功。
- node -v
2. 新建目錄并通過以下命令初始化項目配置 package.json
- npm init
在 package.json scripts: {} 添加以下內(nèi)容:
- "test": "karma start karma.conf.js"
3. 依次安裝測試框架
- npm install karma -g
- npm install jasmine --save-dev
- npm install karma-jasmine --save-dev
- npm install karma-chrome-launcher --save-dev
- npm install jasmine-core --save-dev
或者一次性安裝
- npm install karma -g
- npm install jasmine karma-jasmine karma-chrome-launcher jasmine-core --save-dev
運(yùn)行以下命令新建 karma.conf.js(根目錄下不是必須)
- karma init
文件內(nèi)容及說明:
- /**
- * karma 自動化測試參數(shù)配置
- */
- module.exports = function(config) {
- config.set({
- // 基礎(chǔ)路徑,用在files,exclude屬性上
- basePath: '',
- // 可用的測試框架: https://npmjs.org/browse/keyword/karma-adapter
- frameworks: ['jasmine'],
- // 需要加載到瀏覽器的文件列表
- files: [
- './src/**/*.js',
- './test/unit/specs/*.spec.js'
- ],
- // 排除的文件列表
- exclude: [
- 'karma.conf.js'
- ],
- // 在瀏覽器使用之前處理匹配的文件
- // 可用的預(yù)處理: https://npmjs.org/browse/keyword/karma-preprocessor
- preprocessors: {},
- // 使用測試結(jié)果報告者
- // 可能的值: "dots", "progress"
- // 可用的報告者: https://npmjs.org/browse/keyword/karma-reporter
- reporters: ['progress'],
- // web server port
- port: 9876,
- // 啟用或禁用輸出報告或者日志中的顏色
- colors: true,
- /**
- * 日志等級
- * 可能的值:
- * config.LOG_DISABLE //不輸出信息
- * config.LOG_ERROR //只輸出錯誤信息
- * config.LOG_WARN //只輸出警告信息
- * config.LOG_INFO //輸出全部信息
- * config.LOG_DEBUG //輸出調(diào)試信息
- */
- // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
- logLevel: config.LOG_INFO,
- // 啟用或禁用自動檢測文件變化進(jìn)行測試
- autoWatch: true,
- // 測試啟動的瀏覽器
- // 可用的瀏覽器: https://npmjs.org/browse/keyword/karma-launcher
- browsers: ['Chrome'],
- // 開啟或禁用持續(xù)集成模式
- // 設(shè)置為true, Karma將打開瀏覽器,執(zhí)行測試并***退出
- singleRun: false,
- // 并發(fā)級別(啟動的瀏覽器數(shù))
- concurrency: Infinity,
- // 依賴插件
- plugins: [
- 'karma-chrome-launcher',
- 'karma-jasmine'
- ]
- })
- }
5. 新建源代碼及測試代碼目錄,目錄結(jié)構(gòu)如下:
- project
- - node_modules
- - *(node 模塊)
- - src
- - FQA
- - index.js
- - test
- - unit
- - specs
- - *.spec.js
- - karma.conf.js
- - package.json
6. 測試代碼
。index.js 源碼
- /**
- - test map method callback and parseInt param use
- - @return {[Array]} [Array]
- */
- function checkMap() {
- var nums = ['1', '2', '3'];
- return nums.map(parseInt);
- }
- /**
- - test null is Object,and common object is same
- - @return {[Array]} [Array]
- */
- function typeofAndInstanceOf() {
- var result = [];
- result.push(typeof null);
- result.push(null instanceof Object);
- return result;
- }
- /**
- - 檢測操作符優(yōu)先級
- - @return {[string]} [返回字符串]
- */
- function checkOperators() {
- var result = 'autoTest';
- result = 'Value is ' + (result === 'autoTest') ? 'Something' : 'Nothing';
- return result;
- }
。fqa.spec.js 測試代碼
- /**
- - test index.js checkMap method
- - detail:
- - parseInt(val, base), base is 2 ~ 36, otherwise value equal NaN.
- */
- describe('test map and callback parseInt', function() {
- it('a array call map', function() {
- var nums = checkMap();
- console.log(nums);
- expect([1, NaN, NaN]).toEqual(nums);
- });
- });
- /**
- - test index.js typeofAndInstanceOf method
- - detail:
- - typeof null qeual 'object', but null instanceof Object equal false, because null Constructor not Object.
- */
- describe('test null is object', function() {
- it('null object', function() {
- var result = typeofAndInstanceOf();
- console.log(result);
- expect(['object', false]).toEqual(result);
- });
- });
- /**
- - test index.js checkOperators method
- - detail:
- - compare operator precedence, + gt ?.
- */
- describe('test null is object', function() {
- it('test operator preceence', function() {
- var result = checkOperators();
- console.log(result);
- expect('Something').toEqual(result);
- });
- });
7. 運(yùn)行 sudo npm run test 執(zhí)行測試代碼
- "scripts": {
- "test": "karma start karma.conf.js"
- }
結(jié)果:
解答
1. npm run test 運(yùn)行的實際上是 package.json 中配置的命令:
- "test": "karma start karma.conf.js"
2. describe 定義測試模塊,it 測試一個單元,describe 內(nèi)部可以同時定義多個 it,因此可以做一系列的單元測試,測試方法詳見官方文檔。
3. karma.conf.js 配置 files 設(shè)置測試時需要被加載的文件
- files: [
- './src/**/*.js',
- './test/unit/specs/*.spec.js'
- ]
總結(jié)
希望看完這篇文章,你也能夠動起手來,開始編寫一些單元測試代碼,提高代碼的質(zhì)量,提升自己的周圍影響力。本篇文章內(nèi)容表述了實際項目開發(fā)中會遇到的問題,我們可以通過單元測試來減少這類問題的發(fā)生,以提高代碼的安全性,代碼的質(zhì)量,從而保證產(chǎn)品的穩(wěn)定性。點擊此處查看更多文章。