Web制作、Web開発の歩き方

バックエンドのスタンダード:Laravel入門

■第8話:テスト駆動開発(TDD)の実践

(最終更新日:2024.07.07)

フレームワークのイメージ
この記事は7分で読めます!
(絵が小さい場合はスマホを横に)

「テスト駆動開発でバグを少なく」

テスト駆動開発(TDD)は、ソフトウェア開発における品質保証の手法の一つであり、 コードのバグを減らし、リファクタリングを容易にするために不可欠だ。 この回では、TDDの基本概念を理解し、Laravelにおけるテストの実践方法について学ぶ。 PHPUnitの基礎から始め、フィーチャーテストとユニットテストの違い、テストデータの管理方法、 そしてモックやファクトリの活用法について詳しく解説する。 堅牢で信頼性の高いアプリケーションを構築するためのスキルを身につけよう。


1.PHPUnitの基本

テスト駆動開発 (TDD) とはソフトウェア開発手法の一つで、まずテストケースを作成し、それに基づいてコードを開発するアプローチだ。 この回では、PHPUnitを使用してTDDを実践するための基本を学ぶ。

1.1 PHPUnitとは
PHPUnitは、PHPでのユニットテストを行うためのフレームワークだ。 テスト駆動開発や継続的インテグレーションの一環として、コードの品質を保つために広く利用されている。

1.2 PHPUnitのインストール
まず、プロジェクトにPHPUnitをインストールします。Composerを使用してインストールするのが一般的だ。 インストールには「composer require --dev phpunit/phpunit」をコマンドで実行する。

1.3 PHPUnitの構成
PHPUnitの設定は、プロジェクトルートに phpunit.xml、またはphpunit.xml.distファイルを作成することで行う。 このファイルには、テストの設定やディレクトリの指定が含まれる。 下記では、vendor/autoload.phpによって、Composerでインストールした依存関係がテスト内で利用可能になる。 「Application Test Suite」というテストの名前にしている。 「./tests」ディレクトリ内全てのテストファイルが本テストにあたる。 ということを示している。

phpunit.xmlの例

1.4 テストケースの作成
テストケースはtestsディレクトリに配置する。 PHPUnitのテストクラスは、PHPのクラスとして記述し、TestCaseクラスを継承して実行する。 実行する際は「vendor/bin/phpunit」コマンドを実行する。

テストコードの例

1.5 アサーション
PHPUnitは、テスト結果を検証するための多くのアサーションメソッドを提供する。 以下はそのいくつかだ。

  1. assertTrue($condition):条件がtrueであることを検証
  2. assertFalse($condition):条件がfalseであることを検証
  3. assertEquals($expected, $actual):期待する値と実際の値が等しいことを検証
  4. assertCount($expectedCount, $array):配列やCountableオブジェクトの要素数が期待する数であることを検証

1.6 テスト駆動開発のサイクル
テスト駆動開発のサイクルは以前テスト駆動開発を紹介した記事、ここを参考にしてほしい。 「Red: 失敗するテストを記述」「Green: テストを通すための最小限のコードを記述」 「Refactor: コードをリファクタリングして重複を排除し、コードの質を高める」というサイクルを繰り返す。

1.7 LaravelでのPHPUnitの利用
Laravelでは、デフォルトでPHPUnitがインストールされており、 tests ディレクトリにサンプルのテストケースが用意されている。 Laravel特有のテストヘルパーや機能を利用することで、より簡単にテストを記述できる。

RefreshDatabaseトレイトは、各テストの前後にデータベースのマイグレーションをリセットし、 データベースの状態をクリーンに保つために使用できる。 これにより、テスト間でデータが干渉することを防ぎ、一貫したテスト結果を得ることができる。 また、$response = $this->get('/');では、指定されたURL(ここではルートURL /)に対してGETリクエストを送信する。 Laravelのテスト環境では、これを使ってアプリケーションのルートやコントローラの動作をテストできる。 assertStatus(200) は、HTTPレスポンスのステータスコードが200(OK)であることを確認するアサーションメソッドである。

LaravelにおけるPHPUnitテスト

2.フィーチャーテストとユニットテスト

テスト駆動開発 (TDD) では、テストを先に書いてから実装を行う手法が使われる。 Laravelでのテストには、主に「ユニットテスト」と「フィーチャーテスト」の2種類がある。 それぞれの役割と使い方について詳しく見ていこう。

2.1 ユニットテスト
ユニットテストは、アプリケーションの小さな部分、つまり「ユニット」をテストする。 通常、メソッドやクラス単位でテストを行い、特定の機能が正しく動作するかを確認する。 ユニットテストの特徴としては、範囲が狭く、依存関係が少ない、高速に行えるということがある。 下記の例では、Calculatorクラスのaddメソッドが正しく機能するかをテストしている。 1+2が3であることを確かめている。

ユニットテストの例

2.2 フィーチャーテスト
フィーチャーテストは、アプリケーション全体の動作をテストする。 ユーザーがアプリケーションをどのように操作するかをシミュレートし、 複数のコンポーネントが連携して正しく動作することを確認する。 フィーチャーテストの特徴としては、範囲が広く、依存関係が大きく、シナリオベースのテストとなる。 全体として動作してほしい動きをするかを見る。 下記では、正しいステータスコードが返ってきたか、 test@example.comのメールアドレスを持つデータが登録されたかを確認している。

フィーチャーテストの例

2.3 テストの実行
Laravelでは、次のコマンド「php artisan test」でユニットテストとフィーチャーテストを実行できる。 これにより、tests/Unit および tests/Feature ディレクトリにあるすべてのテストが実行される。

2.4 まとめ
ユニットテストは頻繁に実行して小さな変更を確認し、フィーチャーテストは統合やシナリオ全体の動作を確認するために使う。 このように、ユニットテストとフィーチャーテストを組み合わせることで、TDDを通じて高品質なソフトウェアを開発できる。

3.テスト用データベースの管理

テスト駆動開発 (TDD) を実践する際には、テスト用のデータベースを管理することが重要だ。 Laravelでは、テストのためのデータベース操作を効率的に行うためのさまざまなツールや機能が用意されている。 ここでは、テスト用データベースの管理について詳しく解説する。

3.1 テスト用データベースの設定
テスト用データベースは、通常のデータベースとは別に設定する。 Laravelのphpunit.xmlファイルで、テスト環境用の設定を指定する。 ここでは、テスト用のデータベースとしてSQLiteを使用し、インメモリデータベース (:memory:) を設定する。 これにより、各テストが独立して高速に実行される。

テスト環境用DBの設定

3.2 テストデータの準備
テストデータの準備には、Laravelのファクトリ機能を利用する。 ファクトリは、モデルのインスタンスを簡単に生成するための仕組みである。 まず、ファクトリを作成する。Laravel8以降では、artisanコマンドを使用してファクトリを作成する。

ファクトリ作成コマンド

次に、生成されたファクトリファイル (database/factories/UserFactory.php) を編集して、デフォルトのデータを定義する。 下記では、ユーザ名、メールアドレスとその確認、パスワードとその確認を定義している。

ファクトリの作成

3.3 テストデータの使用
テスト内でファクトリを使用してデータを生成する。 use RefreshDatabaseトレイトをテストクラスに追加することで、 テストが実行されるたびにデータベースがリフレッシュされる。 下記の例では、10人のユーザーを生成し、データベースに10人のユーザーが存在することを確認している。

ユーザーの作成と確認

3.4 マイグレーションの実行
テスト実行時にマイグレーションを実行するためには、RefreshDatabaseトレイトを使用する。 このトレイトは、各テストの前にデータベースをリフレッシュし、最新のマイグレーションを実行する。 使い方は、3.3(上記)で示しているので、確認してほしい。

3.5 シーディング
必要に応じて、テストデータベースにシードデータを挿入することもできる。 シーディングを使用すると、テスト用のデータセットを簡単に準備できる。 下記はシードデータを作成するためのコマンドだ。

シードデータの作成

また、テスト内でシーダーを実行することも可能である。 $this->seed()と書くことで、実行できる。 これにより、初期データが挿入され、次の$this->assertDatabaseHas()で確認することができる。

シードデータの作成

これらの手法を組み合わせることで、効率的にテスト用データベースを管理し、信頼性の高いテストを実行することができる。

4.モックとファクトリ

テスト駆動開発(TDD)において、テストの信頼性を高め、外部依存を排除するために、モックとファクトリを使用することが重要だ。 これにより、テストの対象部分に集中しやすくなる。 ここでは、モックとファクトリの使い方とその役割について詳しく説明する。

4.1 モック
モックとは、テスト対象のオブジェクトが依存する他のオブジェクトの振る舞いを模倣するためのオブジェクトだ。 モックを使うことで外部依存を排除し、テストの対象部分に集中できるようになる。

  1. 依存関係の排除:モデルがデータベースに保存される前に実行する
  2. テストの安定性向上::外部依存によるテストの不安定さを解消する
  3. 特定の条件のシミュレーション:特定の条件や例外をシミュレートして、コードが適切に動作するかを確認する

4.2 モックの使用例
Laravelでは、Mockeryというモックライブラリを使うことが一般的だ。以下は、モックの簡単な例になる。 この例では、PaymentGatewayクラスのchargeメソッドをモックし、PaymentServiceクラスのテストを行っている。

Mocの使用例

4.3 ファクトリ
ファクトリは、テスト用のデータを生成するためのツールだ。 特に、データベース関連のテストにおいて、モデルインスタンスを簡単に作成するために使用される。

  1. テストデータの生成:テスト用のデータを簡単に生成する
  2. 一貫性のあるデータ:一貫性のあるテストデータを提供し、テストの再現性を高める
  3. データセットの拡張:必要に応じて、大量のテストデータを簡単に生成できる

4.4 ファクトリの使用例
ファクトリの使用例は既に3.2~3.4のテストの作成・使用・実行の部分で示した。 Laravelでは、ファクトリを使ってモデルインスタンスを生成する。 ファクトリの作成には「php artisan make:factory UserFactory --model=User」コマンドを使う(3.2参照)。 そして、作成した「database/factories/UserFactory.php」ファイルを編集する(3.3参照)。 そして、10人のユーザーを生成し、データベースに10人のユーザーが存在することを確認する(3.4参照)。

5.まとめ

今回は、テスト駆動開発(TDD)の基本とLaravelにおける実践方法を学んだ。 PHPUnitを用いた基礎的なテストの書き方から始まり、フィーチャーテストとユニットテストの違い、 テストデータの管理方法、そしてモックやファクトリの活用法について詳しく解説した。 これらの技術を駆使することで、バグの少ないコードを効率的に開発し、リファクタリングも容易になる。 TDDを実践することで、信頼性の高いアプリケーションを構築するための基盤を築ける。

▼参考図書、サイト

 「改定2版 速習Laravel」 山田祥寛 WINGSプロジェクト
 「1週間で基礎から学ぶLaravel入門」 Minatomi