概要
Laravelでは標準でPHPUnitが導入されており、簡単にユニットテストができる✅
実際にユニットテストをするまでの流れを簡単に解説する。
フォルダの構造
最初からPHPUnitに関するファイルが用意されているので解説する✅
よく編集するファイル
プロジェクト
|
|----tests
| |
| |----Feature(👈PHPUnitの実行フォルダ)
| | |
| | |----ExampleTest.php
| |
| |----Unit (👈PHPUnitの実行フォルダ)
| | |
| | |----ExampleTest.php
|
|----phpunit.xml (👈PHPUnitの設定ファイル)
FeatureはDB操作ができるが少し重くなる。
テストを実行してみる
サンプルのテストが用意されているのでいきなりテストを試せる✅
以下のコマンドを実行する。
vendor/bin/phpunit
すると以下のようにテストが成功する。
デフォルトのテスト内容
具体的には以下の2ファイルがテストされていた✅
tests/Feature/ExampleTest.php
class ExampleTest extends TestCase
{
public function test_example()
{
$response = $this->get('/');
// トップページのステータスコードが200か?
$response->assertStatus(200);
}
}
tests/Unit/ExampleTest.php
class ExampleTest extends TestCase
{
public function test_example()
{
// 引数がtrueになっているか?
$this->assertTrue(true);
}
}
テストを作ってみる
テスト用のデータベースを設定
テストで本番のデータベースを使うと本番環境が汚染されてしまう。
そのためテスト用のデータデータを設定しておく✅
【方法1】一時的なデータベースを使う
PHPUnitのテストのときだけメモリ上のデータベースを使う設定。
簡易なテストのときにおすすめ!
phpunit.xml
<php>
<server name="APP_ENV" value="testing"/>
<server name="BCRYPT_ROUNDS" value="4"/>
<server name="CACHE_DRIVER" value="array"/>
👇このコメントアウトを解除する!
<!-- <server name="DB_CONNECTION" value="sqlite"/> -->
<!-- <server name="DB_DATABASE" value=":memory:"/> -->
<server name="MAIL_MAILER" value="array"/>
<server name="QUEUE_CONNECTION" value="sync"/>
<server name="SESSION_DRIVER" value="array"/>
<server name="TELESCOPE_ENABLED" value="false"/>
</php>
【方法2】テスト用データベースを使う
テスト環境用のデータベースを設定する方法。
PHPUnit以外でもテストしたいときにおすすめ!
✅まず「database」フォルダに「database_test.sqlite」を新規作成する。
✅その後「.env」ファイルをコピーして「.env_本番環境」などとしておく。
✅「env」の以下を変更する。
# テスト環境用
DB_DATABASE=database_test.sqliteの絶対パス
# 例
# DB_DATABASE=/Applications/MAMP/htdocs/laravel_temp/database/database_test.sqlite
※SQLite以外の場合は適宜データベースに合わせた設定をする必要がある。
【方法3】テスト用データベースを使う(PHPUnitのみ)
PHPUnitのテストのときだけ使うデータベースを設定する方法。
一時的なデータベースでは事足りない場合におすすめ!
✅まず「database」フォルダに「database_test.sqlite」を新規作成する。
✅phpunit.xmlにテスト用のデータベースを設定する。
<php>
<server name="APP_ENV" value="testing"/>
<server name="BCRYPT_ROUNDS" value="4"/>
<server name="CACHE_DRIVER" value="array"/>
<!-- <server name="DB_CONNECTION" value="sqlite"/> -->
<!-- <server name="DB_DATABASE" value=":memory:"/> -->
<server name="MAIL_MAILER" value="array"/>
<server name="QUEUE_CONNECTION" value="sync"/>
<server name="SESSION_DRIVER" value="array"/>
<server name="TELESCOPE_ENABLED" value="false"/>
<!-- テスト用のデータベース -->
<env name="DB_DATABASE" value="database/database_test.sqlite" />
</php>
ファイルを新規作成
artisanコマンドでテストファイルを新規作成できる✅
php artisan make:test 〇〇Test
php artisan make:test HelloTest
を実行した場合
tests/Feature/HelloTest.php が新規作成される
<?php
namespace Tests\Feature;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithFaker;
use Tests\TestCase;
class HelloTest extends TestCase
{
/**
* A basic feature test example.
*
* @return void
*/
public function test_example()
{
$response = $this->get('/');
$response->assertStatus(200);
}
}
--unit
オプションを付けると、tests/Unitディレクトリ内に新規作成される。
【初級】テストコードを記述
PHPUnitの機能だけで基本的なテストをしてみる。
クラスの中身を以下のように変更する。
tests/Feature/HelloTest.php
class HelloTest extends TestCase
{
// メソッド名は「test〇〇」であること
public function testHello()
{
// trueかチェック
$this->assertTrue( true );
// 空かチェック
$arr = [];
$this->assertEmpty( $arr );
// 等しいかチェック
$msg = 'Hello';
$this->assertEquals( 'Hello', $msg );
// 小さいかチェック
$n = random_int( 0, 100 );
$this->assertLessThan( 100, $n );
}
テストを実行する
以下のコマンドを実行する。
vendor/bin/phpunit
すると以下のようにテストが成功する。
以下で詳しく解説している。
【中級】テストコードを記述
Laravelの機能でデータベースを使ったテストをする✅
前提
以下3つが必要。
- テーブル(例:users)
- モデル(例:User)
- Factoryクラス(例:UserFactory)
【補足】Factoryクラスの作り方
artisanコマンドで作成可能✅
php artisan make:factory モデル名
php artisan make:factory Userを実行した場合。
database/factories/UserFactory.php
<?php
namespace Database\Factories;
use App\Models\User;
use Illuminate\Database\Eloquent\Factories\Factory;
class UserFactory extends Factory
{
/**
* The name of the factory's corresponding model.
*
* @var string
*/
protected $model = User::class;
/**
* Define the model's default state.
*
* @return array
*/
public function definition()
{
return [
//
];
}
}
definition関数を編集する。
public function definition()
{
return [
'name' => $this->faker->name(),
'email' => $this->faker->unique()->safeEmail(),
'email_verified_at' => now(),
'password' => Hash::make('12345678'), // password
'remember_token' => Str::random(10),
];
}
テストコードを書く
tests/Feature/HelloTest.php
// Userモデルを使う
use App\Models\User;
class HelloTest extends TestCase
{
// ✅テスト後にデータベースをリセットする
use RefreshDatabase;
// メソッド名は「test〇〇」であること
public function testHello()
{
// ✅レコードが0件かチェック
$this->assertDatabaseCount( 'users', 0 );
// ✅テストユーザーを生成
$user = User::factory()->create([
'name' => 'John',
'email' => '[email protected]',
'email_verified_at' => '2023-04-05 20:39:44',
'password' => Hash::make( '12345678' ),
]);
// ✅レコードが1件かチェック
$this->assertDatabaseCount( 'users', 1 );
}
✅テスト後にデータベースをリセットする
use RefreshDatabase;
と書くだけでPHPUnitを実行後にデータベースをリセットしてくれる。
毎回リセットすることで前回のテスト結果に影響されることがなくなる。
✅レコードが0件かチェック
$this->assertDatabaseCount( 'users', 0 );
でusersテーブルのレコード数を確認している。
0件ならテスト成功!
✅テストユーザーを生成
User::factory()->create(…)
でusersテーブルに1件レコードを作成できる。
引数でカラムの値を設定できる。
未設定のカラムはFactoryによって値が設定される。
→引数をすべて省略することも可能!
✅レコードが1件かチェック
ユーザーを追加したのでレコードが増えているはず。
1件ならテスト成功!
RefreshDatabase
によってレコードが0件に戻る。
テストを実行する
以下のコマンドを実行する。
vendor/bin/phpunit
すると以下のようにテストが成功する。
【上級】テストコードを記述
会員用ページにログインしてアクセスできるかテストする✅
前提
以下3つが必要。( 📄 初心者でもLaravelのユーザー認証が使えるようになる解説 を有効化していること。)
- テーブル(例:users)
- モデル(例:User)
- Factoryクラス(例:UserFactory)
【補足】Factoryクラスの作り方
artisanコマンドで作成可能✅
php artisan make:factory モデル名
php artisan make:factory Userを実行した場合。
database/factories/UserFactory.php
<?php
namespace Database\Factories;
use App\Models\User;
use Illuminate\Database\Eloquent\Factories\Factory;
class UserFactory extends Factory
{
/**
* The name of the factory's corresponding model.
*
* @var string
*/
protected $model = User::class;
/**
* Define the model's default state.
*
* @return array
*/
public function definition()
{
return [
//
];
}
}
definition関数を編集する。
public function definition()
{
return [
'name' => $this->faker->name(),
'email' => $this->faker->unique()->safeEmail(),
'email_verified_at' => now(),
'password' => Hash::make('12345678'), // password
'remember_token' => Str::random(10),
];
}
👆中級と同じ
テストコードを書く
tests/Feature/HelloTest.php
use App\Models\User;
class HelloTest extends TestCase
{
use RefreshDatabase;
// メソッド名は「test〇〇」であること
public function testHello()
{
// ✅未ログイン状態で'/login'にアクセス
$response = $this->get( '/login' );
$response->assertStatus( 200 ); // ステータスコードが200か?
// ✅ログイン処理
$user = User::factory()->create(); // テストユーザーを生成
$this->actingAs( $user ); // ログイン
// ✅ログインした状態で'/login'にアクセス
$response = $this->get( '/login' );
$response->assertStatus( 302 ); // ステータスコードが302か?
}
✅未ログイン状態で'/login'にアクセス
$this->get( '/login' )
でログインページのレスポンスを取得する。
$response->assertStatus( 200 );
でステータスコードが200(正常)か確認する。
✅ログイン処理
User::factory()->create();
でusersテーブルに1件レコードを作成できる。
ユーザーデータの中身はUserFactoryの内容による。
actingAs( $user );
で作成したユーザーでログインする。
✅ログインした状態で'/login'にアクセス
$this->get( '/login' )
でログインページのレスポンスを取得する。
コードは最初と同じだが、さっきログイン処理をした点が異なる。
$response->assertStatus( 302 );
でステータスコードが302(リダイレクト)か確認する。
【補足】ログインする別の方法
actingAs( $user );
ではなく以下でログインすることもできる。
$user = User::factory()->create(); // テストユーザーを生成
// ✅'login'にアクセス + ログイン
$response = $this->post( '/login', [
'email' => $user->email,
'password' => '12345678', // ハッシュ化前のパスワード
] );
$response->assertStatus( 302 ); // ステータスコードが302か?
✅'login'にアクセス + ログイン
$this->post( ‘パス’ , [POST送信するデータ] )
でPOST送信できる。
ここではログインページにPOST送信している。
テストを実行する
以下のコマンドを実行する。
vendor/bin/phpunit
すると以下のようにテストが成功する。
参考サイト
全体的な動作
データベースのリフレッシュ
Laravelで使えるデータベースのassertion