前言
測試程式碼是使程式碼安全的第一步。做到這一點的最好方法之一是使用單元測試,確保應用程式中的每個小功能都能發揮其應有的作用--特別是當應用程式處於邊緣情況,比如無效的輸入,或有潛在危害的輸入。
為什麼要單元測試
說到單元測試,有許多不同的方法。單元測試的一些主要目的是:
- 驗證功能:單元測試確保程式碼做正確的事情,不做不應該做的事情--這是大多數錯誤發生的地方。
- 防止程式碼混亂:當我們發現一個bug時,新增一個單元測試來檢查這個場景,可以保證程式碼的更改不會在將來重新引入這個bug。
- 文件化程式碼:有了正確的單元測試,一套完整的測試和結果提供了一個應用程式應該如何執行的規範。
- 程式碼更安全:單元測試可以檢查可被利用的漏洞(比如那些可以實現惡意SQL隱碼攻擊的漏洞)。
確定範圍
使用單元測試框架使我們能夠快速編寫和自動化我們的測試,並將它們整合到我們的開發和部署過程中。這些框架通常支援在前端和後端的JavaScript程式碼中進行測試。
下面是一些幫助你編寫效能單元測試和可測試程式碼的一般準則。
保持簡短
不要讓你的單元測試冗餘。測試應該只有幾行程式碼,檢查應用程式的程式碼塊。
同時考慮正反面
編寫一個測試來確認一個函式的正確執行是有幫助的。然而,編寫一套更廣泛的測試,檢查一個函式在被誤用時或在邊緣情況下是否會失敗,會更有效果。這些負面測試甚至更有價值,因為它們有助於預測意外情況。例如一個函式什麼時候應該丟擲異常,或者它應該如何處理接收到的畸形資料。
分解複雜功能
含有大量邏輯的大型函式很難測試;包括太多的操作,無法有效測試每個變數。如果一個函式過於複雜,可以將其分割成較小的函式進行單獨測試。
避免網路和資料庫連線
單元測試應該快速且輕量,但是函式會發出網路請求,或者連線其他程式並花很長時間執行。這使得同時執行許多操作具有挑戰性,並可能產生更脆弱的程式碼。你可以在單元測試中造假資料來實現模擬的網路或資料庫呼叫,這可以讓你測試函式的其餘部分。你可以在不同的測試過程中包含真正的網路和資料庫連線,這稱為整合測試。
如何編寫單元測試
現在,我們已經回顧了一些單元測試的最佳實踐,你已經準備好在JavaScript中編寫你的第一個單元測試。
本教程使用了Mocha框架,它是最流行的單元測試之一。每個測試框架都略有不同,但足夠相似,學習基本概念將使你能夠在它們之間切換自如。
要跟著示例,請確保電腦上已經安裝了Node.js。
建立新專案
首先,開啟終端視窗或命令提示符到一個新的專案資料夾。然後,透過輸入npm init -y
在其中建立一個新的Node.js專案。
這會在資料夾內建立package.json
檔案,使你能夠使用npm install -D mocha
將Mocha安裝為開發依賴。
接著,在編輯器中開啟package.json
檔案,用mocha
替換佔位符測試指令碼:
"scripts": {
"test": "mocha"
},
實現一個類
接下來,編寫一個簡單的交通燈系統,進行單元測試。
在專案的目錄內,建立traffic.js
檔案,併為TrafficLight
類新增如下程式碼:
class TrafficLight {
constructor() {
this.lightIndex = 0;
}
static get colors() {
return [ "green", "yellow", "red" ];
}
get light() {
return TrafficLight.colors[ this.lightIndex ];
}
next() {
this.lightIndex++;
// This is intentionally wrong!
if( this.lightIndex > TrafficLight.colors.length ) {
this.lightIndex = 0;
}
}
}
module.exports = TrafficLight;
該類包含了四部分:
TrafficLight.colors
:交通燈顏色的常量屬性。lightIndex
:追蹤當前交通燈顏色索引變數。light
:將當前交通燈顏色作為字串返回的類的屬性。next()
:更改交通燈為下個顏色的函式。
新增單元測試
是時候為程式碼新增單元測試了。
在專案的目錄下建立名為test
的資料夾。這裡是Mocha預設檢查單元測試的地方。在test
資料夾下新增traffic.test.js
檔案。
接著,在檔案頂部匯入TrafficLight
:
const TrafficLight = require( "../traffic" );
我們要用到測試的assert
模組,因此也需要匯入:
const assert = require( "assert" );
在Mocha的幫助下,我們可以使用describe()
函式將單元測試分組。因此我們可以為這個類設定一個頂級組,如下所示:
describe( "TrafficLight", function () {
});
然後,我們在子組中新增校驗交通燈顏色的單元測試,位於TrafficLight
集合內部,並稱為colors
:
describe( "TrafficLight", function () {
describe( "colors", function () {
});
});
對於第一個單元測試,我們可以檢查colors
僅有三個狀態:綠色、黃色和紅色。該測試在describe()
組內部,使用it()
函式定義。因此可以這樣編寫測試用例:
describe( "TrafficLight", function () {
describe( "colors", function () {
it( "has 3 states", function () {
const traffic = new TrafficLight();
assert.equal( 3, TrafficLight.colors.length );
});
});
});
現在,讓我們試著執行單元測試,看看是否可以透過。
在終端視窗中執行npm test
,如果一切正常,Mocha會列印出單元測試執行的結果。
新增更多單元測試
我們的專案現在已經準備好執行單元測試了,因此可以新增更多的單元測試,確保程式碼正確執行。
首先,新增一個單元測試到colors
組,驗證交通訊號燈的顏色是否正確,是否符合順序。下面是實現測試的一種方式:
it( "colors are in order", function () {
const expectedLightOrder = [ "green", "yellow", "red" ];
const traffic = new TrafficLight();
for( let i = 0; i < expectedLightOrder.length; i++ ) {
assert.equal( expectedLightOrder[ i ], TrafficLight.colors[ i ] );
}
});
其次,測試next()
函式,看看訊號燈是否可以正確切換。建立一個新的子組,並新增兩個單元測試:一個用來檢查燈是否按順序正確切換,另一個用來檢查在迴圈到紅色後是否返回到綠色。
按照如下方式編寫單元測試:
describe( "next()", function () {
it( "changes lights in order", function () {
const traffic = new TrafficLight();
for( let i = 0; i < TrafficLight.colors.length; i++ )
assert.equal( traffic.light, TrafficLight.colors[ i ] );
traffic.next();
}
});
it( "loops back to green", function () {
const traffic = new TrafficLight();
// Change the light 3x to go from green -> yellow -> red -> green
for( let i = 0; i < 3; i++ ) {
traffic.next();
}
assert.equal( traffic.light, TrafficLight.colors[ 0 ] );
});
});
現在,當我們重新執行測試時,我們會看到其中一個測試失敗了。這是因為TrafficLight
類中有一個錯誤。
修復bug
再次開啟TrafficLight
類的程式碼,找到next()
函式內的註釋,其內容為// This is intentionally wrong!
。
從我們的單元測試中,我們知道這個函式沒有正確地返回到綠色。我們可以看到,目前的程式碼在lightIndex
值超過交通燈顏色的數量時進行檢查,但索引是從0
開始的。相反,我們必須在該索引值達到顏色數量時返回到綠色。讓我們更新程式碼,當lightIndex
值等於交通燈顏色列表的長度時,將其重置為0
:
// This is intentionally wrong!
if( this.lightIndex === TrafficLight.colors.length ) {
this.lightIndex = 0;
}
現在你所有的單元測試都應該透過。最重要的是,即使TrafficLight
類被重構或大量修改,我們的單元測試也會在它觸達使用者之前捕獲這個錯誤。
總結
單元測試很容易設定,是軟體開發的有效工具。它們有助於早期消除錯誤,並防止它們返回。這使專案更易於管理和維護,即使它們變得更大和更復雜,特別是在更大的開發團隊中。像這樣的自動化測試也使開發人員能夠重構和最佳化他們的程式碼,而不必擔心新程式碼的行為是否正確。
單元測試是開發流程中的一個關鍵部分,對於幫助你構建更好、更安全的JavaScript應用至關重要。
祝你測試愉快!
以上就是本文的所有內容,如果對你有所幫助,歡迎收藏、點贊、轉發~