Node.js 有哪些可以運用的測試框架?
?????♀? 編者按:本文作者是螞蟻集團 Node.js 工程師天豬,首先會介紹下各個部分常用的類庫,在文末將討論下,單元測試是否有必要,歡迎一起探討。

常用的類庫和工具
測試執(zhí)行器
mocha 和 jest 用的比較多。官方新出了個 node test 還在打磨中,未來可期。
覆蓋率統(tǒng)計
像 mocha 這類的還要搭配一個代碼覆蓋率工具。
之前是 istanbuljs,后面作者重寫了個 nyc [1] ,它們主要承擔 2 個職責(zé):一是把代碼進行轉(zhuǎn)譯從而插入打樁代碼,二是支持各種 Reporter 來生成覆蓋率報告。
再后來 V8 內(nèi)置了覆蓋率統(tǒng)計,即無需再轉(zhuǎn)譯代碼了,原生支持覆蓋率數(shù)據(jù)采集。
然后又是這個作者寫了個 c8 [2] 專注于生成覆蓋率報告。

Assert 類庫
校驗變量結(jié)果,必不可少的要用到 assert。
歷史上出現(xiàn)過:expect.js 、should.js、chai 以及 power-assert,jest 也內(nèi)置了自己的 expect。
不過現(xiàn)在 Node.js 官方的 assert/strict 其實也還不錯。
其中 power-assert 是我們 Egg 一直在用的,我很多年前也安利過:《可能是最好的 JS Assert 庫 - 皇帝的新衣》[3]?。
PS:如果要校驗文件內(nèi)容的話,我也寫過一個 assert-file?[4]?。
Mock & Stub 類庫
因為是單元測試,所以經(jīng)常會需要模擬環(huán)境或下游的響應(yīng)。
sinonjs 還不錯,支持 mock 和 stub 等。jest 同樣也內(nèi)置了自己的 mock 庫。
如果是 HTTP 測試的話,nock 很強大,可以幫你 Mock 服務(wù)端響應(yīng)。
不過 Node.js 官方出的 undici 請求庫也內(nèi)置了 Mock 能力。
還有個術(shù)語叫 snapshot,即在運行的時候把數(shù)據(jù) dump 下來,直接作為下次測試的 mock 數(shù)據(jù),能一定程度上提升編寫測試的效率。
HTTP 測試類庫
測試 HTTP Server 場景,必不可少的就是 supertest 這個庫。
命令行測試類庫
Node.js 的一大使用場景是命令行 CLI,如 Webpack、Babel 這些,它們本身也是需要有單測的。
這塊推薦我們寫的:
GitHub - node-modules/clet: Command Line E2E Testing
GitHub - node-modules/coffee: Test command line on Node.js
網(wǎng)頁自動化測試工具
輕量的爬頁面,可以直接用 HTTP 請求庫即可,推薦 undici。
模擬瀏覽器真實執(zhí)行的話,早期是 Selenium 和 phantomjs。
然后 Google 官方出了 puppeteer,由于有 Chromium 的積累,基于 devtools-protocol 協(xié)議,很快就廣受歡迎,干掉了前兩者。同類的競品還有 playwright 和 cypress。
移動端 APP 的話,可以試下 macacajs。
持續(xù)集成服務(wù)
我們寫開源的時候,經(jīng)常需要自動化的持續(xù)集成服務(wù)來幫我們測試。
這個領(lǐng)域的玩家有:Travis 、Appveyor、GitHub Actions 等。
現(xiàn)在基本上都是用 GitHub Actions 了,集成程度太爽了。


探討:單元測試是否有必要?
毋庸置疑,單元測試是非常重要的,它是一名合格的程序員的必要能力和職業(yè)素養(yǎng)。
當然,我們也不是原教旨的 100% 覆蓋率狂徒,很多情況下需要追求 ROI 的平衡點。
1. 寫單元測試很浪費時間?
首先,我先糾正一個常見的錯誤觀點:寫單元測試很浪費時間?
實際上,寫單元測試反而會節(jié)省你的時間,之所以有那個錯誤的觀點,往往之于對比的條件不客觀。我們需要考慮二次修改代碼后,在同等質(zhì)量要求的情況下,回歸的成本。
真實的時間對比,除了考慮『編寫單測的時間』外,容易忽略的是『每次修改代碼后回歸測試的時間』:
寫單測的情況下,回歸測試的時間就是敲一下鍵盤;
而不寫單測的情況下,你需要把代碼更新到應(yīng)用中,然后手動模擬各種情況來測試,譬如要打開瀏覽器,點擊很多不同的地方。
這兩個耗時如何,一目了然。
無非是 前期投入+維護成本+對回歸質(zhì)量的重視程度,權(quán)衡之后的決策,每個公司都有自己的尺度。
當然,我提的很多場景都是 框架類庫(包括前端和 Node.js)、服務(wù)端應(yīng)用、命令行工具等方面,確實在一些變化較大的前端偏 UI 展示的應(yīng)用或者快上快下的活動頁面,對應(yīng)的單測維護成本確實很高,這時候可以基于 ROI 去適當放棄某些非核心分支的單測,這是合理的。
但我們要清楚這是不得已的取舍,而不能去宣稱單元測試沒什么用。
在前端領(lǐng)域還有一種半自動化回歸的測試,就是基于 diff 的方式去自動化對比,然后提醒 Owner 去注意變化影響。這就跟上面那些工具類庫一樣,都是來幫助減少編寫單測的成本的。
2. 單元測試不應(yīng)該程序員寫?
這也是一個錯誤的觀點,單元測試是應(yīng)該程序員自己來寫的,因為是你自己的代碼,要為此而負責(zé),這是一種職業(yè)素養(yǎng)。任何一個稍微有點規(guī)范的團隊,提交代碼都是需要有 CI 測試的,否則無法 有質(zhì)量的 Code Review 協(xié)作。
測試同學(xué)負責(zé)的是集成測試、回歸測試、端到端測試等更大層面的工作。
分工不同,請不要甩鍋。
so...
單元測試很有必要性,編寫單測是程序員的基本職業(yè)素養(yǎng),能寫盡量寫,在個別場景可以根據(jù) ROI 進行取舍。
?? 相關(guān)鏈接
[1] https://github.com/istanbuljs/nyc
[2] https://github.com/bcoe/c8
[3] https://zhuanlan.zhihu.com/p/25956323
[4] https://www.npmjs.com/package/assert-file