Node 單元測試

什麼做這個事情

我在我寫的文章裏面多次提到單元測試的重要性。重要的事情說三遍“單測很重要”、“單測很重要”、“單測很重要”。
單純說這句話沒公信力和權威性,那我舉例子來說明吧。

場景1

某業務線在不斷的版本迭代,在版本6的時候發現功能 A 的代碼太亂太多了。小劉同學打算重構,他辛辛苦苦解決後,打算提交給測試工程師進行測試。測試工程師說“小劉,你這個代碼全是 Bug 呀,我點進去就 Crash”。小劉聽到後很尷尬,心裏想“功能 A 的代碼我寫的很小心,一行行檢查過去的,不可能有問題”。測試說“我點擊商品頁,點擊加入購物車,馬上 Crash 了”。你這個測試被打回,阻塞主流程了。小劉想了想才發現他自己開發的模塊是沒有問題的,但是他在重構功能 A 的時候不小心把依賴功能 A 的地方少傳遞了配置參數 😅

場景2

某公司基礎普通組有小劉同學,在設計某個新技術方案的時候,辛辛苦苦花了3天時間出了技術方案,他去找老闆聊,老闆讓他把思路描述下,再把設計的測試用例給一下。小劉吞吞吐吐講完了設計思路,但是他說還沒有設計測試用例。老闆說你沒測試用例,我怎麼 review 你的設計,一行行看代碼理解邏輯嗎?一句句聽你的設計判斷有沒有問題嗎?以後你找我聽技術設計,你理好設計思路,和測試用例。我看看主流程和一些邊界的輸入輸出,確保這些東西正確那就是沒問題的。我沒有那麼多時間一行行看代碼。(說的也是,組長是 P9 忙得很)

場景3

某公司基礎普通組有小劉同學在做了移動端的 APM 監控和數據上報 SDK 的第一版,但是他很乖,寫好了單元測試。忘了說了小劉同學是負責 iOS 端的,同事做 Android 端的小張同學和他對應,不同就是他沒有寫單元測試的代碼。 需求下來了,需要迭代版本2,小劉和小張都開發好代碼了,需要進行測試。哈哈哈小劉樂壞了,他花了0.5天就測試結束,小張花了1.5天進行測試。爲什麼呢?小劉寫代碼都要寫單元測試代碼,小張不寫。雖然寫單元測試代碼可能需要花一點點時間。但是當新版本迭代的時候就不需要回頭繼續全量測試。他只要按下 Command + U, Xcode 就會跑單元測試相關的代碼。

那單元測試的好處?😂 什麼?你還問好處,上面那麼清晰明瞭,那我再總結下:

  • 確保你寫的代碼的每個分支都可以被覆蓋,防止線上代在用戶端,不小心執行到未知的分支裏面
  • 在進行新版本迭代或者重構的時候,可以集中精力到新邏輯裏面,舊的邏輯可以用 UT 測試覆蓋率來確保
  • 在團隊內進行 code review 或者 merge review 的時候,review 的人可以看代碼中主要邏輯,結合 ut 來判斷。

另外,測試來說一般是結合 CI、CD 的,像我們公司有自己的工具 cli 工具, iOS、Android、RN、React、Vue、Node 項目都一起處理,分析依賴、打包構建(打包系統根據工程特點調度特定打包機)、測試、hot fix、埋點統計、APM等等。

所以如果公司規模小,就寫好 UT 然後結合 lint 做一些處理,公司規模大、開發有能力則需要結合 ci、cd 將測試的能力結合進去。

另外 UT 是一道工序,最好在每個開發者寫代碼的時候做 MR,團隊內 MR +1 數大於3纔可以合併到分支,且 +1 的人裏面必須有一個同一個項目的同學,必須有一個同技術棧且比你高水平的人,MR 指出的問題修改好纔可以合併。且 MR 代碼不能太大,因爲太大,給你做 MR 的同學會很耗費精力。人家閱讀你代碼時間成本太大。

Node 側如何進行 UT 開發

Node 在大學三年級的時候就聽說了,也寫過,之前也用來寫過爬蟲、自動化腳本、cli 等,之前學習過如何在 Node 側寫 ut,這篇文章用來總結下。

舉個例子,有個 Node 工程,一個模塊的主要功能是獲取該目錄下的所有文件。開發代碼如下

// fetchCodeFiles.js
const fs = require('fs-extra'),
    glob = require('glob')

const fetchCodeFiles = async (dirPath) => {
  return new Promise((reslove, reject) => {
    glob('**/*.?(sh|pch|json|xcconfig|mm|cpp|h|m)', { root: dirPath, cwd: dirPath, realpath: true }, (err, files) => {
      if (err) reject(err)
      reslove(files)
    })
  });
}

module.exports = fetchCodeFiles

單元測試該怎麼做?

  1. 在終端下切換到當前工程目錄,安裝 npm install yamljs --save
  2. 在工程根目錄下新建 test 文件夾
  3. 爲你需要的開發文件寫測試代碼。文件命名建議 模塊名稱.test.js
  4. 測試代碼需要引入 assert
  5. 通過 describe 方法、 it 方法、assert 方法描寫測試代碼
  6. 爲了方便測試,在 package.json 文件中的 scripts 下添加描述 "test": "mocha"
  7. 爲了更方便,我使用的是 iterm2,在 .zshrc 文件裏設置別名 alias nt="node test"

提升效率的配置 .zshrc 可以查看文章: Mac 終端效率神技

上面開發代碼的測試代碼如下:

// fetchCodeFiles.test.js
const fetchCodeFiles = require('./../src/fetchCodeFiles'),
    assert = require('assert')

describe("fetch all code files", () => {
    describe("fetch all code files", () => {
        it("should return 12 when code directory is '/Users/liubinpeng/Workspace/search_key/test/code'", (done) => {
            done(assert(fetchCodeFiles('/Users/liubinpeng/Workspace/search_key/test/code')) === 12)
        })
        it("should return 4 when code directory is '/Users/liubinpeng/Workspace/search_key/test/code/Classes'", (done) => {
            done(assert(fetchCodeFiles('/Users/liubinpeng/Workspace/search_key/test/code/Classes')) === 4)
        })
        it("should return 0 when code directory is '/Users/liubinpeng/Workspace/search_key/test/code/EmptyCodeFiles'", (done) => {
            done(assert(fetchCodeFiles('/Users/liubinpeng/Workspace/search_key/test/code/EmptyCodeFiles')) === 0)
        })
    })
})
// package.json

{
  "name": "search",
  "version": "1.0.0",
  "description": "des",
  "main": "index.js",
  "scripts": {
    "test": "mocha",
    "start": "node src/index.js"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "fs-extra": "^8.1.0",
    "glob": "^7.1.6",
    "yamljs": "^0.3.0"
  },
  "devDependencies": {
    "mocha": "^6.2.2"
  }
}

運行結果

測試結果

Mocha

本文主要想說明的是 UT 的重要性,以及 Node 測如何做單元測試。當然 UT 沒這麼簡單,具體深入的不是本文的終點,感興趣的可以查看 Mocha 這個項目的官方文檔

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章