
【初学者向け】Laravelでのテスト – 導入 –
2023.08.01
はじめに
こんにちは、今年の4月に新卒入社したみやです。まずは自己紹介からです。
学生時代はプログラミングを触る機会は多くなく、
ライトコードでエンジニアとして1からスタートしました。
4~6月の3ヶ月間はwebエンジニアとしての基礎知識(HTML/CSS/PHP/SQL)とLaravel(基本部分)を身につける研修を受けました。7月からは実務に携わっていますが、まだまだ勉強中です。
今回は、最近学んだ「Laravelでのテストの作成」について、自身のアウトプットを兼ねて初学者目線で紹介したいと思います。
目次
- 本記事の概要
- テストとは?
- Laravelでのテスト
- まとめ
本記事の概要
はじめにテストについて調査し、整理しています。
次に、Laravelのテストを紹介し、Laravel Breeze のインストール時にデフォルトで作成されるテストを見ながら、Laravelでのテストを理解します。
本記事を通してわかること
・テストについて理解できる。
・Laravelでのテストの作り方がなんとなくわかる。
テストとは?
「テスト」について調べると以下のようなことが出てきます。
ソフトウェアテストとは、開発中のソフトウェア(コンピュータプログラム)が意図した通りに動作するかを検証すること。テストにより欠陥(バグ)が発見されると、原因箇所を探し出して修正するデバッグ(debug)作業が行われる。
引用 : IT用語辞典 e-Words
テストはプログラムが正常に動作するかを検証する方法の一つで、テスト対象が期待通りに動いているかバグがないかを確認できます。
テストには自らプログラムを動かして動作確認する「手動テスト」と検証用のコードにより自動で動作確認する「自動テスト」があります。「手動テスト」でもテストはできますが、総合的な作業量や安全性などさまざまな観点から「自動テスト」の方が有用であり(一概には言えませんが)、本記事では「自動テスト」を題材とします(以降、テスト=自動テスト)。
ただし、テストを書くとなるとシステムを動かすコード以外にテスト用のコードを書く必要になり、労力が増えてしまいます(テストを専門に担当するテスターというエンジニアも存在するそうです)。
当時の感想は「え、面倒くさそう。二度手間みたいで、本当に必要あるの?」でしたが、テストは開発で大きな役割を担っているようです。
テストの必要性
開発において、例えばあるコードを変えたら違う部分の動作が変わってしまうことがあります。テストがないと、変化の原因やどの部分を直せば良いのかを見つけるのが難しくなってしまいます(複数人での大きな開発をイメージすると分かりやすい)。最悪の場合、意図せぬ変化に気づかないままリリースしてしまうことも考えられます。その時にテストがあれば、意図せぬ変化に対応しやすくなります。他にもテストによりバグが早期発見でき、テスト作成のコスト以上にコストを削減できると言ったことも考えられます。このようにバグを生まずにスムーズに開発を行うにはテストが必要になると考えています。
Laravelでのテスト
LaravelにはPHPテストのフレームワークであるPHPUnitが標準搭載されています。Laravelをインストールした段階でPHPUnitがcomposerでインストールされています。実際にvendorディレクトリ(composerによりインストールしたパッケージのソース本体が入っている)にphpunitディレクトリがあることが確認できます。また、LaravelではPHPUnitを使いやすいようにラッパーしたものが用意されています。こちらについては後ほど説明します。
今回はPHPUnitを使ったLaravelのテストを紹介していきます。
動作環境
- M1 Mac (macOs Ventura 13.3.1)
- Docker Desktop for Mac(4.19.0)
環境構築
検証用なのでLaravelアプリケーションを簡単に構築できるLaravel Sailを使って環境構築します(Docker Desktopを事前にインストールしている必要があります)。アプリケーションを作成したいディレクトリに移動し、以下のコマンドでLaravel Sailの新しいアプリケーションを作成します(最後にパスワードを求められるのでPCのパスワードを入力)。
1 | curl -s "https://laravel.build/project" | bash |
上記の通りに実行するとprojectフォルダが作成され、その中にアプリケーションが作成されます(フォルダ名は任意)。また、シェルエイリアスの設定も行っておきましょう(以下、シェルエイリアスの設定を前提)。
次にprojectディレクトリに移動して、 sail up -d コマンドを実行し、Dockerコンテナを立ち上げます。コンテナが立ち上がった後にhttp://localhost/にアクセスし、Laravelのトップページが表示されることを確認します。これでLaravel sailの立ち上げは完了です。
Laravel Breeze
Laravel BreezeとはLaravel公式でスターターキットとして紹介されていて、認証機能が簡単に実装できるパッケージです。本記事ではLaravel Breezeのインスール時にデフォルトで作成されるテストファイルを参照しながら、テストについて理解をしていきます。
では、projectディレクトリにいることを確認し、以下のコマンドでLaravel Breezeをインストールします。
1 2 3 4 5 | sail composer require laravel/breeze --dev sail artisan breeze:install blade sail artisan migrate sail npm install sail npm run dev |
インストールが終わり、再度http://localhost/にアクセスすると、画面右上に「Log in」「Register」が表示されていることを確認して、完了です。
Laravelのテスト作成の流れ
詳しい手順は公式サイトに記載されていますが、簡単に紹介します。
アプリケーションのtestsディレクトリにテストファイルを格納します。
testsディレクトリにはUnitディレクトリとFeatureディレクトリがあります。公式サイトによると、それぞれ以下の特性を持ちます。
ディレクトリ | 格納するテストの種類 | 特徴 |
Unit | 単体テスト | 単一のメソッドをテストすることが多い。アプリケーションのDBやその他のフレームワークサービスにアクセスできない。素のPHPUnitを使う。 |
Feature | 機能テスト | 複数のオブジェクトが相互作用する方法や、JSONエンドポイントへの完全なHTTPリクエストなど、コードの広い部分をテストする。Laravel用に拡張したPHPUnitを使う。 |
テストファイルの作成コマンドは以下の通りです(テストファイル名UserTestは適宜変更する)。
Feature Test を作成
1 | sail artisan make:test UserTest |
Unit Testを作成
1 | sail artisan make:test UserTest --unit |
作成されたテストファイルにはテストによく使うクラスのインポート処理、TestCaseの継承などが既に記述されている雛形が用意されています。このファイルにテストするためのコードを加えていく流れです。
テストの実行
試しにLaravel Breezeインストール時にデフォルトで作成されているテストファイル「tests/Feature/Auth/RegistrationTest.php」をテストしてみましょう。以下のコマンドで実行できます。
1 | sail artisan test tests/Feature/Auth/RegistrationTest.php |
少し待つと以下の画面が表示されます。
デフォルトで作成されているテストなので何も変更していなければ、テストを無事通過します。
画像の Tests: 2 passed (4 assertions) が意味するのは、2つのテストメソッドを実行し、4つのアサーションを行ったという意味です。テストメソッド・アサーションについては次の節で紹介します。
失敗した場合は以下のようにエラーの原因が表示されます。
テストファイル構成
先ほどテストを実行した「tests/Feature/Auth/RegistrationTest.php」を例にテストファイルの構成を紹介します。これは新規ユーザを登録する処理を検証するテストです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | <?php namespace Tests\Feature\Auth; use App\Providers\RouteServiceProvider; use Illuminate\Foundation\Testing\RefreshDatabase; use Tests\TestCase; class RegistrationTest extends TestCase { use RefreshDatabase; public function test_registration_screen_can_be_rendered(): void { $response = $this->get('/register'); $response->assertStatus(200); } public function test_new_users_can_register(): void { $response = $this->post('/register', [ 'name' => 'Test User', 'email' => 'test@example.com', 'password' => 'password', 'password_confirmation' => 'password', ]); $this->assertAuthenticated(); $response->assertRedirect(RouteServiceProvider::HOME); } } |
継承しているクラス
RegistrationTestクラスが今回作成したテストクラスです。このクラスはTests\TestCaseクラスを継承しています。Tests\TestCaseクラスはLaravel用に拡張されたPHPUnit、つまりPHPUnitのラッパーです。これによりLaravelでのテストの記述が容易になっています。一方、単体テストである「tests/Unit/ExampleTest.php」(下画像)を見てみると、ExampleTestクラスがPHPUnit\Framework\TestCaseクラスを継承しています。このクラスは「vendor/phpunit/phpunit/src/Framework/TestCase.php」に存在しており、素のPHPUnitということがわかります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <?php namespace Tests\Unit; use PHPUnit\Framework\TestCase; class ExampleTest extends TestCase { /** * A basic test example. */ public function test_that_true_is_true(): void { $this->assertTrue(true); } } |
テストメソッド
test_registration_screen_can_be_rendered()と test_new_users_can_register() がテストメソッドです。テストを実行した時に Tests: 2 passedと表示されたのは、これら2つのテストメソッドが実行されたからです。メソッド名から分かるように test_registration_screen_can_be_rendered()は登録画面が表示されているかをテストするメソッド、 test_new_users_can_register()は新しいユーザを登録できているかをテストするメソッドです。このように登録という一連の流れを複数のテストメソッドを用いて検証しています。
アサートメソッド
テストメソッドの中で登場するaseert〇〇メソッドはLaravelが提供しているアサートメソッドです。アサートメソッドはある条件を満たしているかどうかを検証するメソッドです。アサートメソッドは様々な種類が存在し、公式サイトで紹介されています。HTTPに関するアサートメソッドの場合、ここで紹介されています。種類が多いので、「tests/Feature/Auth/RegistrationTest.php」で登場するアサートメソッドだけを紹介します。
・assertStatus()
レスポンスに指定HTTPステータスコードがあることをチェックするメソッドです。 $response = $this->get('/register'); で /register にGETリクエストを送信し、返ってきたレスポンスが $request に格納されます。そして、 $response->assertStatus(200); はレスポンスにステータスコード:200があること、つまりリクエストが正常に受け付けられたかどうかを検証しています。
・assertAuthenticated()
ユーザが認証済みであるかを検証するメソッドです。少しユーザの登録処理を行っている「Http/Controllers/Auth/RegisteredUserController.php」のstoreアクションを見てみましょう。詳しくは省略しますが、DBへのユーザの登録処理を行った後にそのユーザでログイン処理をして、 '/dashboard' にリダイレクトさせています。よって、ユーザがログイン状態(認証済み)であれば、正常に登録が完了したことがわかります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | <?php namespace App\Http\Controllers\Auth; use App\Http\Controllers\Controller; use App\Models\User; use App\Providers\RouteServiceProvider; use Illuminate\Auth\Events\Registered; use Illuminate\Http\RedirectResponse; use Illuminate\Http\Request; use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Hash; use Illuminate\Validation\Rules; use Illuminate\View\View; class RegisteredUserController extends Controller { /** * Display the registration view. */ public function create(): View { return view('auth.register'); } /** * Handle an incoming registration request. * * @throws \Illuminate\Validation\ValidationException */ public function store(Request $request): RedirectResponse { $request->validate([ 'name' => ['required', 'string', 'max:255'], 'email' => ['required', 'string', 'email', 'max:255', 'unique:'.User::class], 'password' => ['required', 'confirmed', Rules\Password::defaults()], ]); $user = User::create([ 'name' => $request->name, 'email' => $request->email, 'password' => Hash::make($request->password), ]); event(new Registered($user)); Auth::login($user); return redirect(RouteServiceProvider::HOME); } } |
・assertRedirect()
レスポンスが指定するURIへのリダイレクトであることをチェックするメソッドです。「Providers/RouteServiceProvider.php」を見ると、定数 HOME は '/dashboard' なので、 '/dashboard'にリダイレクトされているかを検証しています。今回の処理ではコントローラで登録処理後に '/dashboard'にリダイレクト処理するように実装しているので、 $response->assertRedirect(RouteServiceProvider::HOME); が通れば正常に処理が行われていることを示せます。
最初は、今回実行されたアサートメソッドは3つであるのにテスト実行後の画面で、 Tests: 2 passed (4 assertions)と4つのアサーションを行ったことになっているのはなぜかと疑問に思いました。これは assertRedirect メソッドに理由があります。 assertRedirect メソッドは「vendor/laravel/framework/src/Illuminate/Testing/TestResponse.php」で定義されていて、内容を見るとassertTrueメソッドとassertLocationメソッドが内部で行われていることがわかります。これにより、 4 assertionsという表示になったと解釈しています(assertRedirectメソッドをコメントアウトしてテストを実行すると、 Tests: 2 passed (2 assertions)になる)。
1 2 3 4 5 6 7 8 9 10 11 12 13 | public function assertRedirect($uri = null) { PHPUnit::assertTrue( $this->isRedirect(), $this->statusMessageWithDetails('201, 301, 302, 303, 307, 308', $this->getStatusCode()), ); if (! is_null($uri)) { $this->assertLocation($uri); } return $this; } |
まとめ
本記事はここまでです。少し中途半端に終わった気もしますが、本記事を見ればなんとなくLaravelのテストが理解できるところまで行けたと思います。今回紹介したテストであれば、手動テスト(登録画面から新規登録を行い、ダッシュボードにリダイレクトされるのを確認・DBに登録されていることの確認を手動でやる)でも問題ないかと思うかもしれませんが、ある機能に対してテストを一回しか行わないということはないでしょう。その時に自動テストがあれば、正確に手間がかからずにテストを行えるはずです。より複雑な処理になってくればなおさらです。
また機会があれば、自分でテストを作る流れやテスト作成中に出現するクラス(RefreshDatabaseなど)やメソッド(setUp)の紹介などより詳しい部分に踏み込んだ記事を書いていきます。
本記事を通して分かったこと
・テストとは?
プログラムが期待通りに動いているか・バグがないかを確認すること。
・Laravelでのテストの作り方は?
アサートメソッドを駆使して、期待する処理がされるか確認するコードを記述してファイルを作成する。
最後までご覧いただきありがとうございました。
書いた人はこんな人

- 社会人一年目のみやです。大学時代はエンジニアとは無縁の生活。ひょんな事からこの業界に興味を持ち、エンジニアとしてライトコードで働いています。未経験ですが、どんどん吸収して成長していきます!
IT技術10月 31, 2023ディープラーニングの勾配計算についてまとめてみた【誤差逆伝播法】
IT技術7月 31, 2023【初学者向け】Laravelでのテスト – 導入 –