はじめに
近況ノートを開発する中で、機能が期待どおりに動くかをテストで確かめてみることにしました。
テストツールにはVitestを選びました。最近よく名前を見かけるようになり、試してみたいと思ったからです。State of JavaScript 2025では、Vitestは使用率ではまだ3位ですが、関心度や継続率などで高い評価を得ています。また、Next.jsの公式ドキュメントにもVitestのセットアップガイドがあります。こうした情報から、成長している選択肢の一つだと感じました。
State of JavaScript 2024
Next.js公式ガイド
テストについて調べていくうちに、振る舞い駆動開発(BDD)という考え方も知りました。今回は厳密にBDDを導入したわけではありませんが、テストを読めば「この機能がどう振る舞うのか」が分かるように書くことを意識しました。
まず、何を確かめたいのか考える
近況ノートには、投稿時にログインしていない場合、ログイン後に投稿を再開できるようにする機能があります。
この動きをテストにするなら、確かめたいことは次のように整理できます。
- 前提:ユーザーはログインしていない
- 操作:近況を投稿する
- 結果:ログイン画面へ移動し、投稿後に再開できる
「どの関数が呼ばれたか」だけでなく、ユーザーの操作と、その結果を考えるのが出発点です。
書いてみたテスト
実際のAPIには接続せず、投稿処理が「ログインが必要」と返すようにして、画面の振る舞いを確認します。
it("未ログインの場合、投稿後にログイン画面へ遷移する", async () => {
// Given: 投稿するとログインが必要な状態
createClassmatePost.mockResolvedValue({ type: "needsLogin" });
render(<NewClassmateForm slug="hanchu" />);
fillRequiredFields();
// When: ユーザーが投稿する
fireEvent.click(
screen.getByRole("button", { name: "近況を投稿する" }),
);
// Then: ログイン後に投稿を再開するルートへ移動する
await waitFor(() => {
expect(push).toHaveBeenCalledWith(
"/login?returnTo=%2Fg%2Fhanchu%2Fpost-login-submit",
);
});
});
ここでは createClassmatePost をモックにしています。テスト中に本物のAPIへ接続する代わりに、投稿処理の結果をこちらで指定しています。
Vitestでは、vi.fn() でモック関数を作り、vi.mock() でモジュールを置き換えられます。非同期処理の結果を指定するには mockResolvedValue() を使います。React Testing Libraryと組み合わせれば、画面を表示して、ボタンを押したときの動きも確かめられます。
Vitestのモックガイド
BDDを知って変わったこと
BDDについて調べる前は、テストは「コードが間違っていないかを確認するもの」というイメージでした。
もちろん、それもテストの役割ですが、今回のように前提・操作・結果の順で書くと、テストから機能のルールも読み取れます。
BDDは、単にテストをGiven/When/Thenの形式で書くことだけではなく、ユーザーや業務から見た振る舞いを例にして、関係者間で共有する考え方です。
今回意識したのは、その入口にあたる「振る舞いをテストで表現する」ことでした。
テストは仕様書の代わりなのか
テストを仕様として読めるようにするといっても、テストですべての仕様を管理する必要はありません。
仕様書には背景や目的、全体のルールを書く。テストでは、その中で特に重要な振る舞いが実際に守られているかを確かめる。そんな役割分担がよさそうと感じました。
テストは、仕様書を置き換えるものではありません。仕様のうち、重要な振る舞いを実行可能な形で補うものだと考えています。
書いてみて感じたこと
モック関数は、APIやデータベースをテスト用の偽物に置き換えるための便利な道具です。ただし、モックした関数が呼ばれたことだけを確認しても、ユーザーにとって機能が正しく動いたかまでは分かりません。
大切なのは、外部処理の結果を制御したうえで、画面や遷移がどうなるべきかを確かめることです。
また、テスト名を「正常に動く」のようにせず、「未ログインの場合、投稿後にログイン画面へ遷移する」と書くと、テストの意図が伝わりやすくなります。実装が変わっても、守りたい振る舞いは何かを残せるのがよいところだと感じました。
さいごに
Vitestでテストを書いてみて、テストは単なる実装のチェックだけではなく、機能の振る舞いを伝えるものにもなると分かりました。
今回は画面や投稿処理の一部をモックにして、決めた条件で振る舞いを確かめました。一方で、実際のブラウザやAPI、データベースまで含めて一連の操作を確認するテストは別の範囲です。Next.jsの非同期Server ComponentについてはVitestでサポートされておらず、公式ガイドでもE2Eテストが推奨されています。今後は必要な機能から、ブラウザを使ったテストも試してみたいです。
テストを読む人が「この機能はどう振る舞うべきか」を理解できるようにする。その意識を持って、少しずつテストを増やしていきたいです。
