首頁  >  文章  >  web前端  >  使用 Jest 的一個範例中的單元、整合和 ETesting

使用 Jest 的一個範例中的單元、整合和 ETesting

DDD
DDD原創
2024-11-20 19:53:15236瀏覽

介紹

許多開發人員在測試程式碼時面臨挑戰。如果沒有適當的測試,錯誤可能會溜走,導致用戶沮喪和昂貴的修復。

本文將向您展示如何在使用 Node.js 和 MongoDB 建構的非常簡單的範例中使用 Jest、Supertest 和 Puppeteer 有效應用單元、整合和端到端測試。

讀完本文,我希望您能夠清楚地了解如何在自己的專案中應用這些類型的測驗。

?‍?請在此儲存庫中找到完整的範例。

介紹我們的依賴關係

在安裝依賴項之前,讓我先介紹一下我們的範例。這是一個非常簡單的範例,用戶可以打開註冊頁面,設定其註冊詳細信息,點擊註冊按鈕,並將其資訊儲存在資料庫中。

在此範例中,我們將使用以下套件:

npm install --save jest express mongoose validator
npm install --save-dev jest puppeteer jest-puppeteer mongodb-memory-server supertest npm-run-all

大多數依賴項都很簡單,但以下是其中一些依賴項的說明:

  • puppeteer:讓您控制無頭瀏覽器 (Chrome) 進行自動化測試和網頁抓取。
  • Jest-Puppeteer: 它是為 Jest 預設的,整合了 Puppeteer,簡化了在瀏覽器環境中執行端對端測試的設定。您可以將其用作 jest.config.js 檔案中的預設,並且可以透過名為 jest-puppeteer.config.js 的檔案自訂 Puppeteer 行為。
  • mongodb-memory-server:它是一個實用程序,可啟動記憶體中的 MongoDB 實例,以快速、獨立地測試資料庫互動。
  • npm-run-all:用於並行或順序運行多個 npm 腳本的 CLI 工具。

單元測試

  • 定義:單元測試著重於單獨測試各個組件或功能。目標是驗證每個程式碼單元是否如預期執行。
  • 速度:單元測試通常非常快,因為它們測試小段程式碼而不依賴外部系統或資料庫。
  • 範例:在我們的使用者註冊範例中,單元測試可能會檢查驗證電子郵件地址的函數。例如,它將驗證該函數是否正確地將 user@example.com 識別為有效,同時拒絕 user@.com 或 user.com。

很好,讓我們將其翻譯成程式碼。

設定單元測試環境

為了執行單元測試而沒有不可預測的行為,您應該在每次測試之前重置模擬函數。您可以使用 beforeEach 掛鉤來實現此目的:

// setup.unit.js

beforeEach(() => {
  jest.resetAllMocks();
  jest.restoreAllMocks();
}); 

測試電子郵件驗證

在本例中,我們要測試 validateInput 函數:

npm install --save jest express mongoose validator
npm install --save-dev jest puppeteer jest-puppeteer mongodb-memory-server supertest npm-run-all

這是一個非常簡單的函數,用於驗證提供的輸入是否包含有效的電子郵件。這是它的單元測試:

// setup.unit.js

beforeEach(() => {
  jest.resetAllMocks();
  jest.restoreAllMocks();
}); 

await Expect(async () => {}).rejects:根據 Jest 文檔,這是期望被拒絕的 Promise 原因的方法。

測試重複的電子郵件

讓我們測試另一個函數,檢查資料庫中是否有重複的電子郵件。實際上,這一點很有趣,因為我們必須處理資料庫,同時單元測試不應該處理外部系統。那我們該怎麼辦呢?好吧,我們應該使用 Mocks。

首先,看看我們需要測試的 emailShouldNotBeDuplicated 函數:

// register.controller.js
const validator = require('validator');

const registerController = async (input) => {
  validateInput(input);
  ...
};

const validateInput = (input) => {
  const { name, email, password } = input;
  const isValidName = !!name && validator.isLength(name, { max: 10, min: 1 });
  if (!isValidName) throw new Error('Invalid name');
  ...
};

如您所見,此函數會向資料庫發送請求以檢查是否有其他使用者俱有相同的電子郵件地址。以下是我們如何模擬資料庫呼叫:

// __tests__/unit/register.test.js
const { registerController } = require('../controllers/register.controller');

describe('RegisterController', () => {
  describe('validateInput', () => {
    it('should throw error if email is not an email', async () => {
      const input = { name: 'test', email: 'test', password: '12345678' };
      await expect(async () => await registerController(input)).rejects.toThrow('Invalid email');
    });
  });
});

我們使用 jest.spyOn(object, methodName) 模擬(監視)資料庫 findOne 方法,該方法建立一個模擬函數並追蹤其呼叫。因此,我們可以使用 toHaveBeenNthCalledWith 來追蹤監視的 findOne 方法的呼叫次數和傳遞的參數。

整合測試

  • 定義:整合測試評估多個元件如何協同工作。它檢查不同功能、模組或服務之間的互動。
  • 速度:整合測試比單元測試慢,因為它們涉及多個元件,並且可能需要資料庫存取或網路呼叫。
  • 範例:對於使用者註冊過程,整合測試可以驗證發送註冊請求時,使用者資料是否已正確驗證並儲存在資料庫中。此測試將確保所有元件(例如輸入驗證、API 端點和資料庫互動)按預期協同工作。

設定整合測試環境

在編寫整合測試之前,我們必須先配置我們的環境:

npm install --save jest express mongoose validator
npm install --save-dev jest puppeteer jest-puppeteer mongodb-memory-server supertest npm-run-all
  • 如您所見,我們匯出testingApp,因為我們在整合測試中需要它。我們將其導出為函數,因為它是在完全初始化之前導出的,因為beforeAll 是異步的,module.exports 語句在testingApp 被賦值之前運行,導致當我們嘗試在測試中使用它時它是未定義的文件。
  • 透過使用 Jest hooks,我們能夠執行以下操作:
    • beforeAll:啟動 Express 伺服器並連接到記憶體 MongoDB 資料庫。
    • afterAll:關閉 Express 伺服器並停止正在執行的記憶體 MongoDB 資料庫。
    • beforeEach:透過在每個測試案例之前刪除使用者集合來清理資料庫。

現在,我們已準備好執行整合測試。

測試註冊 API 請求

讓我們測試整個伺服器端註冊過程——從發送註冊請求到將用戶詳細資訊儲存在資料庫中並重定向到成功頁面:

// setup.unit.js

beforeEach(() => {
  jest.resetAllMocks();
  jest.restoreAllMocks();
}); 

如您所見,registerController 函數整合了多個元件(函數),validateInput、emailShouldNotBeDuplicated 和 createUser 函數。

那麼,讓我們來寫整合測試:

// register.controller.js
const validator = require('validator');

const registerController = async (input) => {
  validateInput(input);
  ...
};

const validateInput = (input) => {
  const { name, email, password } = input;
  const isValidName = !!name && validator.isLength(name, { max: 10, min: 1 });
  if (!isValidName) throw new Error('Invalid name');
  ...
};
  • 如您所見,在此測試案例中,我們使用 supertest 套件向我們的 API 發送註冊請求。這模擬了註冊過程中的真實使用者行為。
  • 在本例中,我們沒有模擬資料庫調用,因為我們需要測試真實的行為。

端對端 (E2E) 測試

  • 定義:端到端測試模擬真實的使用者場景,以驗證整個應用程式從開始到結束的流程。它測試整個應用程序,包括用戶介面和後端服務。
  • 速度:E2E 測試是三種類型中最慢的,因為它們涉及瀏覽應用程式介面並與各種元件交互,通常需要多個網路請求。
  • 範例:在使用者註冊的情況下,E2E 測驗將模擬使用者開啟註冊頁面,填寫詳細資料(如姓名、電子郵件和密碼),然後點選「註冊」按鈕,然後檢查它們是否被重新導向到成功頁面。此測試驗證從使用者的角度來看,註冊過程的每個部分都可以無縫地協同工作。

讓我們開始我們的範例。

搭建端對端測試環境

實際上,在我們的範例中,端到端測試的環境配置與整合測試類似。

從開始到結束的測試註冊過程

在這種情況下,我們需要準確模擬真實的使用者註冊行為,從開啟註冊頁面,填寫詳細資料(姓名、電子郵件、密碼),點擊「註冊」按鈕,最後重新導向到成功頁面。看一下程式碼:

npm install --save jest express mongoose validator
npm install --save-dev jest puppeteer jest-puppeteer mongodb-memory-server supertest npm-run-all

讓我們分解這段程式碼:

  • 有很多工具可以用來實現端到端測試,這裡我們使用 Jest 和 Puppeteer 來實作我們的端對端測試。
  • 您可能想知道什麼是頁面變數?就像 Jest 所期望的那樣,它是 Puppeteer 提供的全域變量,代表瀏覽器中的單一選項卡,我們可以在其中執行導航和與元素互動等操作。
  • 我們使用 Puppeteer 來模擬使用者行為,使用 goto 函數開啟該頁面,使用 type 函數填入輸入,使用 click 函數點選註冊按鈕。

使用不同的配置執行所有測試

Unit, Integration, and ETesting in One Example Using Jest

照片由 Nathan Dumlao 在 Unsplash 上拍攝

此時,您可能想知道當每個測試類型都有自己的配置時如何同時執行所有測試類型。例如:

  • 在單元測試中,您需要在每個測試案例之前重置所有模擬,而在整合測試中,這是不必要的。
  • 在整合測試中,您必須在執行測試之前設定資料庫連接,但在單元測試中,這不是必需的。

那麼,我們如何同時執行所有測試類型,同時確保每個測試類型都遵循其對應的配置?

要解決此問題,請按照以下步驟操作:

1. 讓我們建立三個不同的設定文件,jest.unit.config.js:

// setup.unit.js

beforeEach(() => {
  jest.resetAllMocks();
  jest.restoreAllMocks();
}); 

jest.integration.config.js:

// register.controller.js
const validator = require('validator');

const registerController = async (input) => {
  validateInput(input);
  ...
};

const validateInput = (input) => {
  const { name, email, password } = input;
  const isValidName = !!name && validator.isLength(name, { max: 10, min: 1 });
  if (!isValidName) throw new Error('Invalid name');
  ...
};

jest.e2e.config.js:

// __tests__/unit/register.test.js
const { registerController } = require('../controllers/register.controller');

describe('RegisterController', () => {
  describe('validateInput', () => {
    it('should throw error if email is not an email', async () => {
      const input = { name: 'test', email: 'test', password: '12345678' };
      await expect(async () => await registerController(input)).rejects.toThrow('Invalid email');
    });
  });
});

2. 接下來,更新 package.json 檔案中的 npm 腳本,如下所示:

// register.controller.js
const { User } = require('../models/user');

const registerController = async (input) => {
    ...
  await emailShouldNotBeDuplicated(input.email);
  ...
};

const emailShouldNotBeDuplicated = async (email) => {
  const anotherUser = await User.findOne({ email });
  if (anotherUser) throw new Error('Duplicated email');
};

--config:指定 Jest 設定檔的路徑。

npm-run-all --parallel:允許並行運行所有測試。

3. 然後,建立三個名為 setup.unit.js、setup.integration.js 和 setup.e2e.js 的安裝文件,其中包含前面部分中使用的必要安裝程式碼。
4. 最後,透過執行此命令 npm run test 來執行所有測試。該命令將根據各自的配置並行執行所有單元、整合和端到端測試。

結論

在本文中,我們探討了單元、整合和端到端 (E2E) 測試,強調它們對於建立可靠應用程式的重要性。我們在 Node.js 和 MongoDB 的簡單使用者註冊範例中示範如何使用 Jest、Supertest 和 Puppeteer 來實作這些測試方法。

事實上,可靠的測試策略不僅可以提高程式碼質量,還可以增強開發人員的信心並提高用戶滿意度。

我希望這篇文章為您提供了有用的見解,您可以將其應用到您自己的專案中。測試愉快!

想想

如果您發現本文有用,請查看以下文章:

  • MongoDB GridFS 變得簡單
  • 我如何使用 FFmpeg 和 Node.js 改進視訊串流
  • 4 種處理非同步 JavaScript 的方法

非常感謝您一直陪伴我到現在。我希望您喜歡閱讀這篇文章。

以上是使用 Jest 的一個範例中的單元、整合和 ETesting的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn