Jest入門 - JavaScriptテストの基礎

intermediate | 50分 で読める | 2024.12.23

公式ドキュメント

このチュートリアルで学ぶこと

  • Jestのセットアップ
  • 基本的なテストの書き方
  • マッチャー(アサーション)
  • モックとスパイ
  • 非同期テスト
  • カバレッジレポート

Step 1: セットアップ

実践メモ: ts-jestを使うとTypeScriptのテストを直接実行できます。jest.config.jsでpreset: 'ts-jest'を指定しましょう。

npm init -y
npm install -D jest @types/jest ts-jest typescript
npx ts-jest config:init

jest.config.js

module.exports = {
 preset: 'ts-jest',
 testEnvironment: 'node',
 testMatch: ['**/*.test.ts'],
 collectCoverageFrom: ['src/**/*.ts'],
};

Step 2: 基本的なテスト

// src/math.ts
export function add(a: number, b: number): number {
 return a + b;
}

export function divide(a: number, b: number): number {
 if (b === 0) throw new Error('Division by zero');
 return a / b;
}

// src/math.test.ts
import { add, divide } from './math';

describe('Math functions', () => {
 describe('add', () => {
 it('should add two numbers', () => {
 expect(add(1, 2)).toBe(3);
 });

 it('should handle negative numbers', () => {
 expect(add(-1, 1)).toBe(0);
 });
 });

 describe('divide', () => {
 it('should divide two numbers', () => {
 expect(divide(10, 2)).toBe(5);
 });

 it('should throw error for division by zero', () => {
 expect(() => divide(10, 0)).toThrow('Division by zero');
 });
 });
});

Step 3: マッチャー

// 等値
expect(value).toBe(3); // 厳密等価
expect(obj).toEqual({ a: 1 }); // オブジェクト比較

// 真偽値
expect(value).toBeTruthy();
expect(value).toBeFalsy();
expect(value).toBeNull();
expect(value).toBeDefined();

// 数値
expect(value).toBeGreaterThan(3);
expect(value).toBeLessThanOrEqual(5);
expect(0.1 + 0.2).toBeCloseTo(0.3);

// 文字列
expect(str).toMatch(/pattern/);
expect(str).toContain('substring');

// 配列
expect(arr).toContain(item);
expect(arr).toHaveLength(3);

Step 4: モック

ポイント: `jest.mock()`は外部依存(DB、API)を分離するために利用できます。テスト対象の関数自体をモックしないよう注意しましょう

注意: 必要に応じて各テスト後に`jest.clearAllMocks()`などでモックをリセットし、テスト間の状態漏れを防ぎます。

// src/userService.ts
import { db } from './db';

export async function getUser(id: number) {
 return db.user.findById(id);
}

// src/userService.test.ts
import { getUser } from './userService';
import { db } from './db';

jest.mock('./db');

describe('UserService', () => {
 it('should return user', async () => {
 const mockUser = { id: 1, name: 'Test' };
 (db.user.findById as jest.Mock).mockResolvedValue(mockUser);

 const result = await getUser(1);
 expect(result).toEqual(mockUser);
 expect(db.user.findById).toHaveBeenCalledWith(1);
 });
});

Step 5: 非同期テスト

// async/await
it('should fetch data', async () => {
 const data = await fetchData();
 expect(data).toBeDefined();
});

// Promises
it('should resolve', () => {
 return expect(asyncFunc()).resolves.toBe('value');
});

it('should reject', () => {
 return expect(asyncFunc()).rejects.toThrow();
});

Step 6: テスト実行

# テスト実行
npm test

# ウォッチモード
npm test -- --watch

# カバレッジ
npm test -- --coverage

テストで確認する対象

Jestで大切なのは、実装の細部ではなく振る舞いを確認することです。関数の内部でどの変数を使ったかより、入力に対して期待した出力や副作用が得られるかを見るほうが、リファクタリングに強いテストになります。

最初は正常系だけでもよいですが、慣れてきたら異常系、境界値、空配列、null相当の入力なども確認します。テスト名には「何をしたら、何が起きるか」を書くと、失敗時に原因を追いやすくなります。

書き方の基準

  • 1つのテストで1つの振る舞いを見る
  • モックしすぎて実際の動きから離れないようにする
  • 日付や乱数は固定して再現性を保つ
  • 失敗したときのメッセージが読める粒度にする

まとめ

Jestは使いやすいテストフレームワークで、モック機能も充実しています。テストを書くことでコードの品質と信頼性が向上します。

参考リソース

← 一覧に戻る
PR
PR
PR
PR