筆記:關於爲何要寫單元測試以及快速體驗單元測試

單元測試是什麼

單元測試就是測試最小單元(一個方法,一個組件)。git

爲何要寫單元測試

雖然你們都已經回答過無數次這個問題了,可是那並不表明我確實理解了。github

我之前也沒有寫過單元測試,這也是爲何要來記錄這篇文章的緣由。npm

對於寫單元測試,我我的的直觀感觸是能夠促使本身編寫更「純」的函數或方法。這其實對於代碼的閱讀、維護、重構等都帶來了優惠。你能夠更加明確這個函數的做用,至少會千方百計讓本身的函數所影響的範圍進行縮減、可控。json

再者說,對於 CI/CD,單元測試又是很是有必要的一個環節。bash

我也相應的搜索了一些網絡上小夥伴們的解答,你們無外乎都是在圍繞着可閱可用易於重構自我提高這些方面在闡述,總之寫單元測試是一件好的事情,若是你有能力有時間,那麼請嘗試一下而且持續的寫下去吧。網絡

測試工具

通過一些查閱,mocha + chai 彷彿是一個比較廣泛的選擇。框架

mocha 是一個測試框架,它對異步代碼的追蹤測試頗有自信。異步

chain 是一個斷言庫函數

此外還有一個 jest,它是一個大而全的測試框架,它使用內置的 matchers 斷言。工具

mocha + chai

初始化一個測試項目

# 新建一個文件夾
mkdir mocha-chai
# 進入文件
cd mocha-chai
# 初始化
npm init -y
# 安裝
yarn add mocha chai

接下來準備一個源碼文件 index.js 和 測試文件 index.spec.js

新建 index.js

// index.js
module.exports.getAbs = (x, y) => {
  return Math.abs(x - y)
}

新建 index.spec.js

爲何必須是 .spec.js?我去查了一下,結果以下:

約定俗成的術語。
Unit Testing Specification(單元測試基準)的縮寫,不少框架默認回去找這些後綴的文件。

官方也給出一段相關的內容,不太肯定是否還有其餘處。

Test files can be specified using spec, e.g., "spec": "test/**/*.spec.js".
// index.spec.js
const assert = require('chai').assert
const getAbs = require('./index').getAbs

describe('to test getAbs()', () => {
  it('should return 1 when the value is 1,2', () => {
    assert.equal(getAbs(1, 2), 1, 'getAbs(1,2) equal 1')
  })
  it('should return 1 when the value is 2,1', () => {
    assert.equal(getAbs(2, 1), 1, 'getAbs(2,1) equal 1')
  })
  it('should return 0 when the value is 1,1', () => {
    assert.equal(getAbs(1, 1), 0, 'getAbs(1,1) equal 0')
  })
})

修改 package.json

主要是 test 命令:

"scripts": {
    "test": "mocha index.spec.js"
},

run mocha

執行:

yarn test
yarn run v1.21.1
$ mocha index.spec.js


  to test getAbs()
    √ should return 1 when the value is 1,2
    √ should return 1 when the value is 2,1
    √ should return 0 when the value is 1,1


  3 passing (8ms)

Done in 0.46s.

未經過的 mocha

如今,在 index.spec.js 文件中追加一個 it()

it('should return 0 when the value is not present', () => {
    assert.equal(getAbs(), 0, 'getAbs() equal 0')
})

以後再次執行:

yarn test
yarn run v1.21.1
$ mocha index.spec.js


  to test getAbs()
    √ should return 1 when the value is 1,2
    √ should return 1 when the value is 2,1
    √ should return 0 when the value is 1,1
    1) should return 0 when the value is not present


  3 passing (18ms)
  1 failing

  1) to test getAbs()
       should return 0 when the value is not present:

      getAbs() equal 0
      + expected - actual

      -NaN
      +0

      at Context.<anonymous> (index.spec.js:15:12)
      at processImmediate (internal/timers.js:439:21)



error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

總之就是未獲得預期的值得意思,很明顯這是由於沒有傳遞參數致使的。也就是說在不給函數傳遞參數的時候,函數的行爲有些不符合預期的效果。

因此稍做修改再來一次。

修改 index.js

// index.js
module.exports.getAbs = (x = 0, y = 0) => {
  return Math.abs(x - y)
}

再次執行結果以下:

yarn run v1.21.1
$ mocha index.spec.js


  to test getAbs()
    √ should return 1 when the value is 1,2
    √ should return 1 when the value is 2,1
    √ should return 0 when the value is 1,1
    √ should return 0 when the value is not present


  4 passing (7ms)

Done in 0.47s.

因此說,實際上 unit testing 視狀況來看,須要編寫不少的斷言,上面的測試雖然是經過了,但實際上還有有其餘的問題存在的,極端點來說好比傳遞的參數並非一個數字:

it('should return 0 when the value is not a number', () => {
    assert.equal(getAbs([1, 2, 3], 3), 0, 'getAbs() equal 0')
})

JavaScript 並不像強類型語言那樣強硬,因此不少時候即使是錯誤的使用一個函數也只有在執行起來以後才能浮現錯誤。

嗯...因此說,單元測試中的斷言所能覆蓋的狀況要相對比較普遍才能夠,不然也只是片面的結論而已。

總感受一不當心就會走火入魔...

小結

unit testing 目的是爲了使程序更加的健壯,穩定。可是相應的是須要編寫更多的代碼才能達到這個目的,因此如何正確的把握這個度,應該是一個值得思考的問題。

因此也只有更多的實踐才能夠找出一個比較滿意的答案吧。

相關文章
相關標籤/搜索