測試代碼是確保代碼穩(wěn)定的第一步。能做到這一點的最佳方法之一就是使用單元測試,確保應(yīng)用程序中的每個較小的功能都按應(yīng)有的方式運行——尤其是當(dāng)應(yīng)用程序接收到極端或無效輸入,甚至可能有害的輸入時。

為什么要進行單元測試?

進行單元測試有許多不同的方法,一些主要目的是:

  • 驗證功能:單元測試確保代碼做正確的事情并且不做任何不應(yīng)該做的事情——大多數(shù)錯誤發(fā)生在這里。
  • 防止代碼回歸:當(dāng)我們發(fā)現(xiàn)錯誤時,添加單元測試來檢查場景可以防止代碼更改在將來重新引入錯誤。
  • 記錄代碼:通過正確的單元測試,一套完整的測試和結(jié)果提供了應(yīng)用程序應(yīng)該如何工作的規(guī)范。
  • 保護您的應(yīng)用程序:單元測試可以檢查可利用的漏洞(例如啟用惡意 SQL 注入的漏洞)。

范圍界定和編寫單元測試

使用單元測試框架使我們能夠快速編寫和自動化我們的測試,并將它們集成到我們的開發(fā)和部署過程中。這些框架通常支持前端和后端 JavaScript 代碼的測試。

以下是幫助你編寫性能單元測試和可測試代碼的一些通用指南。

保持單元測試簡短而簡單

不要編寫過重的單元測試,測試應(yīng)該只有幾行代碼來檢查應(yīng)用程序的簡短功能塊。

考慮正面和負(fù)面的測試用例

雖然編寫正確執(zhí)行函數(shù)的測試是有用的,但是,編寫更廣泛的測試集來檢查函數(shù)在被濫用或在極端情況下是否正確或者失敗同樣重要。這些負(fù)面測試可能更有價值,因為它們有助于預(yù)測意外情況,例如函數(shù)何時應(yīng)引發(fā)異常或應(yīng)如何處理接收格式錯誤的數(shù)據(jù)。

分解長而復(fù)雜的函數(shù)

包含大量邏輯的大型函數(shù)難以測試;包含太多操作則難以有效地測試每個變量。如果函數(shù)太復(fù)雜,請將其拆分為較小的函數(shù)以進行單獨測試。

避免網(wǎng)絡(luò)和數(shù)據(jù)庫連接

單元測試應(yīng)該是快速和輕量級的,但是進行網(wǎng)絡(luò)調(diào)用或連接到其他應(yīng)用程序或進程的功能需要長時間才能執(zhí)行。這使得同時運行多個操作變得具有挑戰(zhàn)性,且會產(chǎn)生更脆弱的代碼。你可以在單元測試中調(diào)用模擬的網(wǎng)絡(luò)或數(shù)據(jù)庫而非真實地連接網(wǎng)絡(luò)。而如果要進行包含真實的網(wǎng)絡(luò)和數(shù)據(jù)庫連接的測試,應(yīng)當(dāng)在稱為集成測試(所有的單元或模塊被組合在一起并作為一個整體進行測試)中進行而不是單元測試。

如何編寫單元測試

我們已經(jīng)回顧了一些單元測試的最佳實踐,現(xiàn)在準(zhǔn)備好用 JavaScript 編寫你的第一個單元測試了。

本教程使用 Mocha 框架 —— 最流行的單元測試之一。每個測試框架都略有不同,但它們足夠相似,學(xué)習(xí)基本概念將使你能夠輕松地在它們之間切換。

在開始前,請確保你的電腦上安裝了 Node.js 環(huán)境。

創(chuàng)建一個新項目

首先打開一個終端窗口或命令提示符到一個新的項目文件夾。然后,通過以下命令在其中創(chuàng)建一個新的 Node.js 項目。

npm init -y

這會在文件夾中創(chuàng)建一個文件 package.json ,使你能夠使用 npm install -D mocha 命令來安裝 mocha 框架。

接下來,在代碼編輯器中打開 package.json 文件并將 test script 替換為:mocha

  "scripts": {
    "test": "mocha"
  },

實現(xiàn)一個類

接下來,編寫一個簡單的紅綠燈系統(tǒng)進行單元測試。

在項目目錄中,創(chuàng)建一個名為 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:一個變量,跟蹤當(dāng)前交通燈顏色的索引。
  • light:以字符串形式返回當(dāng)前交通燈顏色的類屬性。
  • next():將紅綠燈更改為下一個燈光顏色的功能。

配置和添加我們的第一個單元測試

現(xiàn)在是時候圍繞代碼添加一些單元測試了。

在項目中創(chuàng)建一個名為 test 的目錄,這是 Mocha 默認(rèn)檢查單元測試的地方。然后,在新的測試文件夾中添加一個名為 traffic.test.js 的文件。

接下來,在文件頂部導(dǎo)入 TrafficLight 類:

const TrafficLight = require( "../traffic" );

我們還將使用該 assert 模塊進行測試,因此在你的代碼中需要引入它:

const assert = require( "assert" );

Mocha 中我們可以使用 describe() 這個函數(shù)將單元測試進行分組集合,如下:

describe( "TrafficLight", function () {

});

然后,我們將創(chuàng)建一些單元測試來驗證他們自己的子組中的交通顏色:

describe( "TrafficLight", function () {
    describe( "colors", function () {
    });
});

對于第一個單元測試,我們可以驗證 colors 只有三種狀態(tài):綠色、黃色和紅色。測試方式是使用 describe() 組內(nèi)的 it() 函數(shù)定義的,因此編寫測試如下:

describe( "TrafficLight", function () {
    describe( "colors", function () {
        it( "has 3 states", function () {
            const traffic = new TrafficLight();
            assert.equal( 3, TrafficLight.colors.length );
        });
    });
});

現(xiàn)在讓我們運行單元測試,看看它是否通過。

在終端窗口中運行 npm test,如果一切正確,Mocha 會打印出單元測試運行的結(jié)果。

詳解如何用JavaScript編寫一個單元測試

添加更多單元測試

我們的項目現(xiàn)在已準(zhǔn)備好運行單元測試,因此我們可以添加更多測試以確保我們的代碼正常工作。

首先,向colors組中添加一個單元測試,以驗證紅綠燈顏色是否正確且有序。這是實現(xiàn)此測試的一種方法:

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()方法看它是否正確地改變了交通信號燈。創(chuàng)建一個新的子組并添加兩個單元測試:一個檢查燈光是否以正確的順序變化,另一個檢查燈光是否能循環(huán)在紅燈之后變?yōu)榫G燈:

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 ] );
    });
});

現(xiàn)在,當(dāng)我們重新運行測試時,我們會看到其中一個測試失敗了。這是因為 TrafficLight 類中有一個錯誤。

詳解如何用JavaScript編寫一個單元測試

修復(fù)錯誤

為方便調(diào)試本例提前注明好的錯誤代碼位置,我們再次打開 TrafficLight 類并找到 next() 函數(shù)內(nèi)的這句注釋:// This is intentionally wrong!

從單元測試中我們知道這個函數(shù)沒有正確地循環(huán)回 green,我們可以看到代碼是在判斷lightIndex值超過交通燈顏色的數(shù)量時給索引設(shè)置了0,這顯然是不對的,我們必須在值達(dá)到確切的顏色數(shù)時立即將索引修改為0

// This is intentionally wrong!
if( this.lightIndex === TrafficLight.colors.length ) {
    this.lightIndex = 0;
}

現(xiàn)在你所有的單元測試都應(yīng)該通過了。而這帶來的好處是即使TrafficLight這個類被重構(gòu)或大量修改,我們的單元測試也會在它到達(dá)用戶之前捕獲這個錯誤。

詳解如何用JavaScript編寫一個單元測試

最后

單元測試易于設(shè)置,是軟件開發(fā)的有效工具。它們有助于及早消除錯誤并防止它們重現(xiàn)。這使項目更易于管理和維護,即使它們變得更大更復(fù)雜——尤其是在大型開發(fā)團隊中。像這樣的自動化測試還使開發(fā)人員能夠重構(gòu)和優(yōu)化他們的代碼,而不必?fù)?dān)心新代碼的行為是否正確。

以上就是詳解如何用JavaScript編寫一個單元測試的詳細(xì)內(nèi)容,更多關(guān)于JavaScript單元測試的資料請關(guān)注其它相關(guān)文章!

原文地址:https://juejin.cn/post/7160827470474641421