在 Node.js 中收集程式碼覆蓋率

Node.js 透過其測試執行器為程式碼覆蓋率提供了內建支援,可以使用 --experimental-test-coverage 標誌啟用。

如果使用 run() API,則必須將 coverage 選項設定為 true。有關 run() API 的更多資訊,請參閱 node:test 文件

什麼是程式碼覆蓋率?

程式碼覆蓋率是測試執行器的一項指標,用於衡量程式原始碼在測試期間被執行的程度。它揭示了程式碼庫的哪些部分被測試了,哪些沒有,有助於找出測試套件中的空白。這確保了對軟體進行更全面的測試,並最大限度地降低了未被發現的錯誤的風險。通常以百分比表示,程式碼覆蓋率越高表示測試覆蓋越徹底。有關程式碼覆蓋率的更詳細解釋,您可以參閱維基百科“程式碼覆蓋率”條目

基本覆蓋率報告

讓我們透過一個簡單的例子來演示程式碼覆蓋率在 Node.js 中是如何工作的。

注意:本示例以及本檔案中的所有其他示例均使用 CommonJS 編寫。如果您不熟悉此概念,請閱讀 CommonJS 模組文件。

function (, ) {
  return  + ;
}

function () {
  return  % 2 === 0;
}

function (, ) {
  return  * ;
}

. = { , ,  };

在模組中,我們有三個函式:addisEvenmultiply

在測試檔案中,我們正在測試 add()isEven() 函式。請注意,multiply() 函式未被任何測試覆蓋。

要在執行測試時收集程式碼覆蓋率,請參見以下程式碼片段

node --experimental-test-coverage --test main.test.js

執行測試後,您將收到一份如下所示的報告

✔ add() should add two numbers (1.505987ms)
✔ isEven() should report whether a number is even (0.175859ms)
ℹ tests 2
ℹ suites 0
ℹ pass 2
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 59.480373
ℹ start of coverage report
ℹ -------------------------------------------------------------
ℹ file         | line % | branch % | funcs % | uncovered lines
ℹ -------------------------------------------------------------
ℹ main.js      |  76.92 |   100.00 |   66.67 | 9-11
ℹ main.test.js | 100.00 |   100.00 |  100.00 |
ℹ -------------------------------------------------------------
ℹ all files    |  86.96 |   100.00 |   80.00 |
ℹ -------------------------------------------------------------
ℹ end of coverage report

覆蓋率報告詳細說明了您的程式碼有多少被測試所覆蓋

  • 行覆蓋率:測試期間執行的程式碼行百分比。
  • 分支覆蓋率:被測試的程式碼分支(如 if-else 語句)的百分比。
  • 函式覆蓋率:在測試期間被呼叫的函式百分比。

在此示例中

  • main.js 顯示 76.92% 的行覆蓋率和 66.67% 的函式覆蓋率,因為 multiply() 函式未被測試。未覆蓋的行 (9-11) 對應於此函式。
  • main.test.js 在所有指標上都顯示了 100% 的覆蓋率,這表明測試本身已完全執行。

包含和排除

在開發應用程式時,您可能會遇到需要排除某些檔案或程式碼行的情況。

Node.js 提供了處理此問題的機制,包括使用註釋來忽略特定的程式碼部分以及使用命令列排除整個模式。

使用註釋

function (, ) {
  return  + ;
}

function () {
  return  % 2 === 0;
}

/* node:coverage ignore next 3 */
function (, ) {
  return  * ;
}

. = { , ,  };

使用修改後的 main.js 檔案報告覆蓋率時,報告現在將顯示所有指標均為 100% 覆蓋。這是因為未覆蓋的行 (9-11) 已被忽略。

有多種方法可以使用註釋來忽略程式碼部分。

function (, ) {
  return  + ;
}

function () {
  return  % 2 === 0;
}

/* node:coverage ignore next 3 */
function (, ) {
  return  * ;
}

. = { , ,  };

這些不同的方法都將生成相同的報告,所有指標的程式碼覆蓋率均為 100%。

使用命令列

Node.js 提供了兩個命令列引數,用於管理在覆蓋率報告中包含或排除特定檔案。

--test-coverage-include 標誌(在 run() API 中為 coverageIncludeGlobs)將覆蓋範圍限制為與提供的 glob 模式匹配的檔案。預設情況下,會排除 /node_modules/ 目錄中的檔案,但此標誌允許您明確地包含它們。

--test-coverage-exclude 標誌(在 run() API 中為 coverageExcludeGlobs)會從覆蓋率報告中忽略與給定 glob 模式匹配的檔案。

這些標誌可以多次使用,當兩者同時使用時,檔案必須遵守包含規則,同時也要避開排除規則。

.
├── main.test.js
├── src
│   ├── age.js
│   └── name.js

在上面的報告中,src/age.js 的覆蓋率不甚理想,但使用 --test-coverage-exclude 標誌(在 run() API 中為 coverageExcludeGlobs),可以將其完全從報告中排除。

node --experimental-test-coverage --test-coverage-exclude=src/age.js --test main.test.js

我們的測試檔案也包含在此覆蓋率報告中,但我們只想要 src/ 目錄中的 JavaScript 檔案。在這種情況下,可以使用 --test-coverage-include 標誌(在 run() API 中為 coverageIncludeGlobs)。

node --experimental-test-coverage --test-coverage-include=src/*.js --test main.test.js

閾值

預設情況下,當所有測試都透過時,Node.js 會以程式碼 0 退出,表示執行成功。但是,可以配置覆蓋率報告,在覆蓋率不達標時以程式碼 1 退出。

Node.js 目前支援為所有三種覆蓋率設定閾值

如果您想要求前一個示例的行覆蓋率 >= 90%,您可以使用 --test-coverage-lines=90 標誌(在 run() API 中為 lineCoverage: 90)。

node --experimental-test-coverage --test-coverage-lines=90 --test main.test.js