- 適用於 JDK 23 的 GraalVM (最新)
- 適用於 JDK 24 的 GraalVM (搶先體驗)
- 適用於 JDK 21 的 GraalVM
- 適用於 JDK 17 的 GraalVM
- 封存
- 開發版本
程式碼覆蓋率命令列工具
GraalVM 提供程式碼覆蓋率命令列工具,讓使用者可以記錄並分析程式碼特定執行時的原始碼覆蓋率。
程式碼覆蓋率,以原始碼行數、函式或陳述式覆蓋的百分比表示,是了解特定原始碼執行的重要指標,通常與測試品質 (測試覆蓋率) 相關聯。為單行程式碼提供視覺化的覆蓋率概觀,讓開發人員了解哪些程式碼路徑已涵蓋,哪些尚未涵蓋,深入了解執行的特性,例如,可以作為進一步測試工作的依據。
以下範例應用程式將用於示範 GraalVM 的程式碼覆蓋率功能。此應用程式定義了一個 getPrime
函式,使用基於埃拉托斯特尼篩法演算法的基本質數計算器來計算第 n 個質數。它還具有前 20 個質數的簡陋快取。
- 將以下程式碼複製到名為
primes.js
的新檔案中
class AcceptFilter {
accept(n) {
return true
}
}
class DivisibleByFilter {
constructor(number, next) {
this.number = number;
this.next = next;
}
accept(n) {
var filter = this;
while (filter != null) {
if (n % filter.number === 0) {
return false;
}
filter = filter.next;
}
return true;
}
}
class Primes {
constructor() {
this.number = 2;
this.filter = new AcceptFilter();
}
next() {
while (!this.filter.accept(this.number)) {
this.number++;
}
this.filter = new DivisibleByFilter(this.number, this.filter);
return this.number;
}
}
function calculatePrime(n) {
var primes = new Primes();
var primesArray = [];
for (let i = 0; i < n; i++) {
primesArray.push(primes.next());
}
return primesArray[n-1];
}
function getPrime(n) {
var cache = [2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71];
var n = arguments[0];
if (n > cache.length) { return calculatePrime(n); }
return cache[n-1];
}
// TESTS
console.assert(getPrime(1) == 2);
console.assert(getPrime(10) == 29);
請注意,最後幾行是斷言,將其視為單元測試。
-
執行
js primes.js
。範例應用程式應該不會列印任何輸出,因為所有斷言都通過了。但是斷言對實作的測試有多徹底呢? - 執行
js primes.js --coverage
以啟用程式碼覆蓋率。程式碼覆蓋率工具應為範例應用程式列印如下輸出js primes.js --coverage -------------------------------------------------------- Code coverage histogram. Shows what percent of each element was covered during execution -------------------------------------------------------- Path | Statements | Lines | Roots -------------------------------------------------------- /path/to/primes.js | 20.69% | 26.67% | 22.22% --------------------------------------------------------
追蹤器會為每個原始檔列印覆蓋率直方圖。您可以看到陳述式覆蓋率約為 20%,行覆蓋率約為 26%,而根覆蓋率 (術語「根」涵蓋函式、方法等) 為 22.22%。這告訴您,我們的簡單測試並不太擅長執行原始碼。接下來您將找出程式碼的哪些部分未涵蓋。
- 執行
js primes.js --coverage --coverage.Output=detailed
。準備好看到一些冗長的輸出。將輸出指定為detailed
將列印所有原始碼行,並在開頭加上覆蓋率註釋。由於輸出可能很大,建議將此輸出模式與--coverage.OutputFile
選項結合使用,將輸出直接列印到檔案。我們的範例應用程式的輸出如下
js primes.js --coverage --coverage.Output=detailed
--------------------------------------------------------
Code coverage per line of code and what percent of each element was covered during execution (per source)
+ indicates the line is covered during execution
- indicates the line is not covered during execution
p indicates the line is part of a statement that was incidentally covered during execution
for example, a not-taken branch of a covered if statement
--------------------------------------------------------
Path | Statements | Lines | Roots
/path/to/primes.js | 20.69% | 26.67% | 22.22%
class AcceptFilter {
accept(n) {
- return true
}
}
class DivisibleByFilter {
constructor(number, next) {
- this.number = number;
- this.next = next;
}
accept(n) {
- var filter = this;
- while (filter != null) {
- if (n % filter.number === 0) {
- return false;
- }
- filter = filter.next;
}
- return true;
}
}
class Primes {
constructor() {
- this.number = 2;
- this.filter = new AcceptFilter();
}
next() {
- while (!this.filter.accept(this.number)) {
- this.number++;
}
- this.filter = new DivisibleByFilter(this.number, this.filter);
- return this.number;
}
}
function calculatePrime(n) {
- var primes = new Primes();
- var primesArray = [];
- for (let i = 0; i < n; i++) {
- primesArray.push(primes.next());
}
- return primesArray[n-1];
}
function getPrime(n) {
+ var cache = [2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71];
+ var n = arguments[0];
p if (n > cache.length) { return calculatePrime(n); }
+ return cache[n-1];
}
// TESTS
+ console.assert(getPrime(1) == 2);
+ console.assert(getPrime(10) == 29);
--------------------------------------------------------
正如輸出開頭的圖例所解釋的,執行涵蓋的行會以 +
開頭。未涵蓋的行會以 -
開頭。部分涵蓋的行會以 p
開頭 (例如,當 if
陳述式被涵蓋,但只採用一個分支時,請考慮將另一個分支視為偶然涵蓋)。
查看輸出,您可以看到 calculatePrime
函式及其所有呼叫都永遠不會執行。再次查看斷言和 getPrime
函式,很明顯我們的測試始終會命中快取。因此,大部分程式碼永遠不會執行。您可以改進這一點。
- 在
primes.js
檔案的末尾新增console.assert(getPrime(30) == 113);
並執行js primes.js --coverage
。由於新增的斷言會以 30 呼叫getPrime
(我們的快取只有 20 個條目),覆蓋率將如下所示
js primes.js --coverage
-------------------------------------------------------
Code coverage histogram.
Shows what percent of each element was covered during execution
-------------------------------------------------------
Path | Statements | Lines | Roots
-------------------------------------------------------
/path/to/primes.js | 100.00% | 100.00% | 100.00%
-------------------------------------------------------
與其他工具整合 #
程式碼覆蓋率工具提供與其他工具整合的方法。使用 --coverage.Output=lcov
執行會以常用的 lcov 格式產生輸出,該格式由多個工具 (例如,genhtml
) 用於顯示覆蓋率資料。請參閱下一個範例,其中顯示如何使用 Visual Studio Code 可視化 Node.js 應用程式的覆蓋率。
- 將以下程式碼複製到名為
nodeapp.js
的新檔案中
const express = require('express')
const app = express()
const port = 3000
app.get('/', (req, res) => {
res.send('Hello World!')
})
app.get('/neverCalled', (req, res) => {
res.send('You should not be here')
})
app.get('/shutdown', (req, res) => {
process.exit();
})
app.listen(port, () => console.log(`Example app listening on port ${port}!`))
- 安裝 express 模組相依性
$JAVA_HOME/bin/npm install express
-
啟動 Visual Studio Code 並安裝支援 lcov 的程式碼覆蓋率外掛程式。此範例使用 程式碼覆蓋率醒目提示器,但其他外掛程式也應以類似方式運作。
- 啟用並設定覆蓋率後,執行 nodeapp.js 檔案
$JAVA_HOME/bin/node --coverage --coverage.Output=lcov \ --coverage.OutputFile=coverage/lcov.info \ nodeapp.js
請注意,程式碼覆蓋率醒目提示器外掛程式預設會在 coverage
目錄中尋找 lcov.info
檔案,因此請將程式碼覆蓋率工具的輸出導向該目錄。
-
在瀏覽器中瀏覽 localhost:3000/,然後瀏覽 localhost:3000/shutdown 以關閉應用程式。
-
開啟 Visual Studio Code,然後開啟包含
nodeapp.js
檔案和coverage
目錄的資料夾,您應該會看到類似以下的影像
如果您希望將 GraalVM 程式碼覆蓋率工具收集的資料與您自己的視覺化整合,--coverage.Output=json
選項會導致輸出為 JSON 檔案,其中包含追蹤器收集的原始資料。