自動テストチュートリアル

Playwright、Seleniumなどの自動テストツールを学ぼう

テストシナリオの構成と読み解き方

まずは実物を見てみよう:テストコードの全体像

テストコードの全体像

一見すると複雑に見えるかもしれませんが、ご安心ください。次のセクションから、このコードがどのようなルールで組み立てられているのかを、一つずつ丁寧に紐解いていきます。

本格的な実装(【実行:Act】)に挑戦するのは後のレッスンからです。その前にテストの骨格となる【準備:Arrange】と【検証:Assert】の考え方について学んでいきましょう。


コードの冒頭にある import とは?

※今回の課題では使用しませんが、知識として覚えておくと役立ちます。

プログラミングにおけるimportは、大工さんが作業を始める前に、道具箱から「カナヅチ」や「ノコギリ」といった必要な道具を取り出して準備する作業に似ています。

Playwrightでテストを書く際も、最初に「こんな道具を使ってテストを書きますよ!」という宣言が必要なのです。

import { expect } from "@playwright/test";

Playwrightという大きな「公式ツールボックス」から、『expect(結果をチェックするための虫眼鏡)』という道具を取り出しています。

import { test } from "@setup/test";

こちらは、このプロジェクト専用に用意された「特注ツールボックス(@setup/test)」から、『test(テストの土台となる設計図)』という道具を取り出しています。

今は、「importは、テストで使うお決まりの道具を準備しているんだな」という程度の理解で全く問題ありません。


シナリオを構成する2つの主役:describe() と test()

Playwrightのテストシナリオは、物語を組み立てるように、主に2つの要素で構成されています。

describeとtest

describe():物語の「タイトル」

項目 内容
役割 関連するテストを一つのグループにまとめる「大見出し」です
例え 「第一章:ログイン機能に関するテスト」のように、テストの大きなテーマを宣言します
メリット 「ログイン」や「商品購入」のように機能単位でテストをまとめることで、テスト全体の見通しが非常に良くなります

test():物語の「各エピソード」

項目 内容
役割 テストしたい一つの具体的なシナリオ(=テストケース)です。これが実際に実行されるテストの最小単位になります
例え 「正しい情報でログインできる」「パスワードを間違えるとエラーが表示される」といった、物語の中の個別のエピソードにあたります

テストの基本3ステップ「準備 → 実行 → 検証」

テストシナリオは、基本的に以下の3つのステップで構成されています。これはテストにおける非常に重要な考え方で、「Arrange-Act-Assert (AAA)」 とも呼ばれます。

ステップ 英語 説明
準備 Arrange テストを実行するための前準備をする段階。例:ログインページを開く、サインアップする、テスト用のデータを準備する など
実行 Act テストしたい操作を実際に行う段階。例:メールアドレスとパスワードを入力して、ログインボタンをクリックする など
検証 Assert 実行した結果が、期待通りになったかを確認する段階。例:「ようこそ、山田さん」というメッセージが表示されていることを確認する など

この「準備 → 実行 → 検証」の流れを意識するだけで、テストコードの目的が格段に分かりやすくなります。


具体的なテストの例

言葉だけだと少し分かりにくいかもしれませんので、具体的なテストの例を見て、この3ステップのイメージを掴みましょう。

テストの例①: 登録したデータがテーブルに表示されていることを確認する

ステップ 内容
準備 ユーザー登録を済ませておく
実行 新しいデータを登録する
検証 登録したデータがテーブルに表示されていることを確認する

テストの例②: 登録済みデータを編集できることを確認する

ステップ 内容
準備 ユーザー登録と、編集対象のデータ登録を済ませておく
実行 登録済みのデータを編集する
検証 データが正しく編集されていることを確認する

例②のように、テストしたい内容(実行)によっては、準備することが多くなるのが分かりますね。

実際のソースコードでは画像のようになります。これは1つのテストファイルに、2つのテストシナリオがある場合のAAAです。後ほど詳しく説明するので今はさっと見るだけで問題ありません。

AAAパターンの実例

共通の「準備」をまとめる機能:beforeEach() / beforeAll()

マイページの機能をテストする際に毎回「ログイン」が必要になるケースのように、複数のテストケースで同じ「準備」が必要な場合、beforeEach()beforeAll() を使うと、コードを非常にすっきりとまとめることができます。

関数 実行タイミング
beforeEach() ファイル内の各テストが実行される直前に 毎回 実行されます
beforeAll() ファイル内の最初のテストが始まる前に 一度だけ 実行されます

beforeEach() の使用例

テストシナリオに入る前に、必ず beforeEach() の中の処理が実行されています。

今回の場合、テストシナリオが3つあるので、3回 beforeEach() に入っていることがターミナルの結果からわかります。

beforeEachの例

beforeAll() の使用例

テスト実行時、1度だけ beforeAll() の中の処理が実行されています。

こちらはテストシナリオが3つありますが、1回のみ beforeAll() に入っていることがターミナルの結果からわかります。

beforeAllの例

準備フェーズの考え方

「準備」がないテストもある?

あります。 例えば「ログインページを開き、ログインできることを確認する」という単純なテストでは、「ページを開く」準備と「ログインを試す」実行がほぼ一体化しています。

このように、テストの目的によっては、明確な「準備」フェーズを設けないこともあります。

beforeEach() や beforeAll() は、いつ使うべき?

ここで悩むかもしれませんが、原則はとてもシンプルです。

「ファイル内の複数のテストシナリオで、全く同じ準備が必要な場合(要はデータを使い回す)」に使うのが基本です。

beforeEach()beforeAll() の一番の目的は、同じ準備コードの繰り返しをなくし、コードを綺麗に保つことだからです。

ファイル内にテストシナリオが1つしかない場合は?

理屈上は、テストシナリオが1つなら繰り返しがないので beforeEach()/beforeAll() は不要です。

しかし、現場によっては、準備と実行の分離を明確にするため、あえて beforeEach()/beforeAll() で準備を囲むルールを採用していることもあります。

なのでチームのルールに従いましょう。 迷ったときは、プロジェクト内の他のテストコードを読んで、書き方を真似するのが最も確実な方法です。


このレッスンで覚えておいてほしいこと

関数 役割
describe() 関連テストをまとめる「大見出し(タイトル)」を書くところ
test() 1つの具体的な「テストケース(エピソード)」を書くところ
beforeEach() test() の前に必ず実行される処理
beforeAll() グループの最初の test() の前に一度だけ実行される処理

この4つの役割を覚えてもらえたらOKです!