mocha の使い方 — JavaScriptの柔軟なテストフレームワーク
一言でいうと
mocha は、Node.js およびブラウザ環境で動作する、シンプルかつ柔軟なJavaScript/TypeScriptテストフレームワークです。BDD・TDD・QUnitなど複数のテストスタイルをサポートし、アサーションライブラリやレポーターを自由に組み合わせて使えます。
どんな時に使う?
- Node.jsアプリケーションのユニットテスト・統合テストを書きたい時 — Express/Fastifyなどのバックエンドロジックのテストに最適です
- アサーションライブラリやモックライブラリを自分で選びたい時 — Jestのようなオールインワンではなく、chai・sinon・nockなどを自由に組み合わせたい場合に向いています
- 既存プロジェクトのテスト基盤がmochaで構築されている時 — 長い歴史を持つフレームワークのため、レガシー〜中規模プロジェクトで広く採用されています
インストール
# npm
npm install --save-dev mocha
# yarn
yarn add --dev mocha
# pnpm
pnpm add --save-dev mocha
TypeScriptで使う場合は型定義も追加します。
npm install --save-dev @types/mocha
基本的な使い方
ディレクトリ構成
project/
├── src/
│ └── math.ts
├── test/
│ └── math.test.ts
├── package.json
└── .mocharc.yml
テスト対象のコード
// 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;
}
テストコード
mocha はアサーションライブラリを同梱していないため、Node.js 組み込みの assert や chai などを別途使います。ここでは Node.js 標準の assert を使用します。
// test/math.test.ts
import assert from "node:assert/strict";
import { add, divide } from "../src/math.js";
describe("add", () => {
it("2つの正の数を加算できる", () => {
assert.equal(add(1, 2), 3);
});
it("負の数を加算できる", () => {
assert.equal(add(-1, -2), -3);
});
});
describe("divide", () => {
it("正常に除算できる", () => {
assert.equal(divide(10, 2), 5);
});
it("ゼロ除算でエラーをスローする", () => {
assert.throws(() => divide(10, 0), {
message: "Division by zero",
});
});
});
設定ファイル
# .mocharc.yml
require:
- tsx
spec: "test/**/*.test.ts"
timeout: 5000
補足: TypeScriptを直接実行するために
tsxやts-nodeなどのローダーが必要です。npm install --save-dev tsxでインストールしてください。
実行
// package.json
{
"scripts": {
"test": "mocha"
}
}
npm test
出力例:
add
✓ 2つの正の数を加算できる
✓ 負の数を加算できる
divide
✓ 正常に除算できる
✓ ゼロ除算でエラーをスローする
4 passing (12ms)
よく使うAPI
1. describe / it — テストスイートとテストケースの定義
最も基本的なBDDスタイルのインターフェースです。
describe("User", () => {
describe("#save()", () => {
it("データベースにユーザーを保存できる", async () => {
const user = new User({ name: "Alice" });
const result = await user.save();
assert.equal(result.name, "Alice");
});
});
});
2. before / after / beforeEach / afterEach — フック(セットアップ・ティアダウン)
テストの前後に実行する処理を定義します。
import assert from "node:assert/strict";
describe("Database操作", () => {
let db: Database;
before(async () => {
// テストスイート全体の前に1回だけ実行
db = await Database.connect("test_db");
});
after(async () => {
// テストスイート全体の後に1回だけ実行
await db.disconnect();
});
beforeEach(async () => {
// 各テストケースの前に毎回実行
await db.clear();
});
afterEach(() => {
// 各テストケースの後に毎回実行
console.log("テストケース完了");
});
it("レコードを挿入できる", async () => {
await db.insert({ id: 1, name: "Alice" });
const count = await db.count();
assert.equal(count, 1);
});
});
3. .only / .skip — テストの絞り込みとスキップ
デバッグ時に特定のテストだけ実行したり、一時的にスキップしたりできます。
describe("Feature A", () => {
// このテストだけ実行される
it.only("重要なテスト", () => {
assert.equal(1 + 1, 2);
});
// スキップされる(.onlyがある場合もスキップ)
it("別のテスト", () => {
assert.equal(2 + 2, 4);
});
});
describe("Feature B", () => {
// 明示的にスキップ(pending扱い)
it.skip("未実装のテスト", () => {
// TODO: 後で実装
});
});
注意:
.onlyをコミットに含めないよう注意してください。CIで全テストが実行されなくなります。--forbid-onlyフラグをCI環境で使うと安全です。
4. this.timeout() / this.retries() — タイムアウトとリトライ
テストごとにタイムアウトやリトライ回数を制御できます。
describe("外部API連携", function () {
// スイート全体のタイムアウトを設定
this.timeout(10000);
// 不安定なテストのリトライ回数を設定
this.retries(3);
it("APIからデータを取得できる", async function () {
// 個別のテストでタイムアウトを上書き
this.timeout(15000);
const response = await fetch("https://api.example.com/data");
assert.equal(response.status, 200);
});
});
注意: アロー関数
() => {}ではthisが束縛されないため、this.timeout()などを使う場合はfunction() {}を使ってください。
5. 非同期テスト — Promise / async-await / コールバック
mocha は複数の非同期パターンをサポートしています。
// async/await(推奨)
it("async/awaitでテストできる", async () => {
const data = await fetchData();
assert.deepEqual(data, { id: 1, name: "Alice" });
});
// Promiseを返す
it("Promiseを返してテストできる", () => {
return fetchData().then((data) => {
assert.deepEqual(data, { id: 1, name: "Alice" });
});
});
// コールバック(done)
it("コールバックでテストできる", (done) => {
fetchDataWithCallback((err, data) => {
if (err) return done(err);
try {
assert.deepEqual(data, { id: 1, name: "Alice" });
done();
} catch (e) {
done(e);
}
});
});
類似パッケージとの比較
| 特徴 | mocha | Jest | Vitest |
|---|---|---|---|
| アサーション | 外部ライブラリ(chai等) | 組み込み(expect) | 組み込み(expect互換) |
| モック | 外部ライブラリ(sinon等) | 組み込み(jest.fn) | 組み込み(vi.fn) |
| スナップショットテスト | プラグインで対応 | 組み込み | 組み込み |
| コードカバレッジ | 外部(nyc / c8) | 組み込み(--coverage) | 組み込み(c8 / v8) |
| ESM対応 | ○ | ○(設定が必要な場合あり) | ◎(ネイティブ) |
| 設定の自由度 | ◎(高い) | ○(中程度) | ○(中程度) |
| 実行速度 | ○ | ○ | ◎(Vite活用) |
| 学習コスト | やや高い(組み合わせが必要) | 低い(オールインワン) | 低い(Jest互換API) |
| ブラウザテスト | ○(ネイティブ対応) | jsdom | ○(ブラウザモード) |
選定の目安:
- 新規プロジェクト → Vitest(Vite利用時)または Jest が第一候補
- アサーション・モックを自分で選びたい → mocha
- 既存のmochaプロジェクトの保守 → そのまま mocha を継続
注意点・Tips
1. アロー関数と this の問題
mocha のコンテキスト(this.timeout() など)を使う場合、アロー関数は使えません。
// ❌ NG: アロー関数ではthisが使えない
describe("example", () => {
it("test", () => {
this.timeout(5000); // TypeError
});
});
// ✅ OK: function式を使う
describe("example", function () {
it("test", function () {
this.timeout(5000);
});
});
this を使わないテストであればアロー関数で問題ありません。
2. CIでの --forbid-only と --exit
{
"scripts": {
"test": "mocha",
"test:ci": "mocha --forbid-only --exit"
}
}
--forbid-only:.onlyが残っていたらエラーにする--exit: テスト完了後にプロセスを強制終了する(DB接続やタイマーが残っている場合に有用)
3. .mocharc.yml で設定を一元管理する
# .mocharc.yml
require:
- tsx
spec: "test/**/*.test.ts"
timeout: 5000
recursive: true
reporter: spec
forbid-only: false # CIではtrueに
コマンドライン引数を毎回書く必要がなくなります。package.json の "mocha" キーでも設定可能です。
4. chai との組み合わせ
mocha と最もよく組み合わせて使われるアサーションライブラリが chai です。
npm install --save-dev chai @types/chai
import { expect } from "chai";
describe("chai との組み合わせ", () => {
it("expectスタイルでアサーションできる", () => {
expect([1, 2, 3]).to.have.lengthOf(3);
expect({ name: "Alice" }).to.deep.equal({ name: "Alice" });
expect(() => { throw new Error("fail"); }).to.throw("fail");
});
});
5. レポーターの変更
# ドット表示(CI向け)
mocha --reporter dot
# 最小表示
mocha --reporter min
# JSON出力
mocha --reporter json
# nyan cat(お楽しみ)
mocha --reporter nyan
まとめ
mocha は「テストランナーに徹し、それ以外は自分で選ぶ」という Unix 哲学的な設計のテストフレームワークです。アサーション・モック・カバレッジツールを自由に組み合わせられる柔軟性が最大の強みですが、その分セットアップにはやや手間がかかります。新規プロジェクトでは Jest や Vitest も有力な選択肢ですが、既存の mocha ベースのプロジェクトでは引き続き安定して活用できるフレームワークです。