Skip to main content

単体テストマニュアル 2 - 最初の単体テストを作成する

· 4 min read

単体テストの最小単位

単体テストでは、関数ではなく、機能を最小単位としてテストすべきです。

関数を単位としてテストする問題点

伝統的な単体テストでは、関数を単位としてテストします。

  1. 私的なメソッドとエクスポートされていない関数

    エクスポートされていない場合、テストが困難になります。

    エクスポートすると、モジュールのカプセル化に影響します。

    結果として、これらの私的なメソッドはテストされなくなることが多いです。

  2. 関数ごとにテストを行う場合、後にロジックの構造を調整する必要が生じた場合、テストの構造も変更する必要があります。

    これにより、機能のメンテナンスに加えて、テストのメンテナンスも必要になります。

機能を単位として

単位レベルの機能テストTest Driven Development: By Example に由来します。

正しいアプローチは、機能を単位として単体テストを行うことです。

各関数に対して単体テストを書くのではなく、一つの機能を単位としてテストを書きます。

システムは様々な機能で構成されており、機能を単位としてテストすることで、具体的な機能実装のロジック構造を調整しても、テストを変更する必要がなくなります。

これにより、私的なメソッドに対するテストも不要になります。

機能を単位とした単体テストはより丈夫です。

単体テストを作成する四つのステップ

Steps
1. テスト用データを準備givenArrange(準備)
2. テスト対象の機能/関数を呼び出すwhenAct(実行)
3. 機能の出力を検証thenAssert(検証)
4. ティアダウン

Arrange-Act-Assert (AAA) パターンに従う:準備(Arrange)、実行(Act)、アサート(Assert)。

第一歩と第四歩は必ずしも必要ではありませんが、第二歩と第三歩は必要です。

例えば、sayHi をテストする時に、データの準備は必要ありません。

function sayHi() {
console.log("Hi!");
}

テスト中にはグローバルなデータやキャッシュを扱うことがありますが、これらは後で元に戻す必要があります。 これがティアダウンの役割です。

しかし、そのようなデータに関わらない場合は、ティアダウンは必要ありません。

最初の単体テストを作成する

以下の単体テストを行ごとにコメントで解説します。

import { test, expect } from "vitest";
import { useTodoStore, reset } from "../todo.ts";

// テストケースは説明的な英語で記述し、テストの目的を明確になるようにします。
test("add todo", () => {
// 1. テスト用データを準備
const todoStore = useTodoStore();
const title = "eat";

// 2. テスト対象の機能/関数を呼び出す
useTodoStore.addTodo(title);

// 3. 機能の出力を検証
expect(todoStore.todos[0].title).toBe(title);

// 4. ティアダウン
reset();
});