Node.js Supertest:打造可靠的 Express API 整合測試系統

單元測試 (Unit Test) 檢查的是齒輪零件是否正確,而 整合測試 (Integration Test) 檢查的是整台機器是否能順利運作。在 Node.js 中,Supertest 是模擬 HTTP 請求、驗證 API 路由、中間件攔截與回傳格式的標準工具。

關鍵的前置作業:拆分 App 與 Server

為了讓測試框架能夠「冷啟動」你的應用程式而不需要佔用真實的網路埠口 (Port),你必須將 Express 的定義與 listen 指令分離。

1. app.js (定義路由與邏輯)

const express = require('express');
const app = express();

app.get('/api/welcome', (req, res) => {
  res.status(200).json({ message: 'Welcome to our API!' });
});

module.exports = app;

2. server.js (實際啟動服務)

const app = require('./app');
app.listen(3000, () => console.log('Server is running...'));

實戰:撰寫 API 整合測試

安裝 Supertest:npm install --save-dev supertest

建立測試檔案 tests/api.test.js

const request = require('supertest');
const app = require('../app');

describe('API 整合測試實戰', () => {
  test('GET /api/welcome 應該回傳 200 與正確的 JSON', async () => {
    // 使用 request(app) 模擬請求
    const response = await request(app).get('/api/welcome').set('Accept', 'application/json');

    // 驗證狀態碼與內容
    expect(response.status).toBe(200);
    expect(response.body.message).toBe('Welcome to our API!');
    expect(response.headers['content-type']).toMatch(/json/);
  });

  test('造訪未定義的路徑應該回傳 404', async () => {
    const response = await request(app).get('/not-exists');
    expect(response.status).toBe(404);
  });
});

測試需要登入的 API (Headers 與 Token)

在測試保護路由時,你可以透過 .set() 帶入模擬的驗證資訊:

test('POST /api/profile 帶入 Token 應成功', async () => {
  const response = await request(app)
    .post('/api/profile')
    .set('Authorization', 'Bearer fake-token-123')
    .send({ nickname: 'NewName' });

  expect(response.status).toBe(200);
  expect(response.body.success).toBe(true);
});

配合資料庫的測試流程 (Hooks)

在進行 API 測試時,通常會涉及資料庫讀寫,這時可以使用 Jest 的生命週期鉤子:

beforeAll(async () => {
  // 建立資料庫測試連線或插入基礎資料 (Seed)
});

afterAll(async () => {
  // 測試完畢後清空資料庫並關閉連線
});

總結

  1. 整合測試 確保了路由、邏輯與中間件之門的協作沒有任何瑕疵。
  2. 透過 Supertest,你可以在不真正啟動伺服器的情況下,進行極速的 API 功能驗證。
  3. 始終保持 App 與 Server 分離 的設計架構,這是測試友好的代碼象徵。