🐕

【Jest】Express.jsのミドルウェアとして作成したモジュールの単体テスト

2023/03/30に公開

Express.jsのミドルウェアとして作成したモジュールの単体テストについてのメモです。

環境

  • Express.js 4.18.2
  • TypeScript 5.0.2
  • jest 29.5.0
  • sinon 15.0.3
  • sinon-express-mock 2.2.1

考え方

  • 単体テストとして以下を確認できればよさそう
    • expressのRequest, Responseオブジェクトの中身の確認
    • NextFunctionが呼ばれることの確認
  • 内部で別の関数やメソッドを呼んでいる場合は別途モック化する

準備

  • expressのRequest, Responseオブジェクトの中身の確認のため、expressのRequest, Responseのモックを用意する
    • sinon-express-mockライブラリを使用する
  • NextFunctionが呼ばれることの確認のため、NextFunctionのスパイを用意する
    • sinonライブラリを使用する
npm i -D sinon-express-mock sinon @types/sinon-express-mock @types/sinon

スパイとは

関数やメソッドが呼び出された回数や呼び出された順番、引数を検証するために使用するオブジェクトです。

以下の記事が非常に参考となりました。ありがとうございます。

https://gotohayato.com/content/483/#テストスパイ

ミドルウェアとテストコードのサンプル

HTTPヘッダの x-user-idから値を取得して、Responseオブジェクトの locals.userIdにセットするだけのミドルウェアです。
HTTPヘッダの x-user-idがない場合は例外を発生させます。

サンプルのミドルウェア

import { Request, Response, NextFunction } from 'express';

export const middlewareSample = (req: Request, res: Response, next: NextFunction) => {
  const userId = req.headers['x-user-id'];
  if (!userId || userId === '') throw new Error();
  
  res.locals.userId = userId;
  next();
}

テストコード

import { middlewareSample } from '../expressMiddleware';
import sinon from 'sinon';
import { mockReq, mockRes } from 'sinon-express-mock'

describe('myMiddleware', () => {
  it('should call next()', () => {
    const req = mockReq(
      // HTTPリクエストのヘッダーを設定
      {
        headers: {
          "x-user-id": "12345"
        }
      }
    );
    const res = mockRes();
    // スパイ:関数が呼ばれたかどうか、何回呼ばれたか、などをチェック(監視)するためのモノ
    const next = sinon.spy();

    middlewareSample(req, res, next);

    // next()が呼ばれたことを確認する
    expect(next.calledOnce).toBe(true);
    // res.locals.userIdが正しいことを確認する
    expect(res.locals.userId).toBe("12345");
  });

  it('should not call next()', () => {
    const req = mockReq(
      {
        headers: {
          "x-user-id": ""
        }
      }
    );
    const res = mockRes();
    const next = sinon.spy();

    // 例外が発生することを確認する
    expect(()=>middlewareSample(req, res, next)).toThrowError();

    // next()が呼ばれなかったことを確認する
    expect(next.calledOnce).toBe(false);
  });
});

以上です。

GitHubで編集を提案
NCDCエンジニアブログ

Discussion