Laravelでphpunitを利用したテスト
phpunitでテストを書いてみる。
テストの自動化というか、DevOpsというか、システム作りもシステム化していくべきで、こういう対応は大事だと思う。
ただ、テストを自動化することの是非について、仕事としての判断が入ってくると喧嘩する人たちが出てくるので注意が必要。
個人的にはテストコードを書かなくて良いのは、一回だけ動けばいいようなプログラムくらいだと思う。(ただし、テスト自体は必要)
そうではないプログラムのテストを書かない方が良いと言う人は、真面目にテストしてなくてテストの大変さを知らないんじゃないかと思う。
あと、テストコードを必須にすれば、コードを書き逃げするプログラマに対しての牽制にもなりそうかな。
phpunitの確認
Laravelには標準でphpunitが入っているらしいので、とりあえずバージョン確認。
phpunit --version PHPUnit 9.5.6 by Sebastian Bergmann and contributors.
9.5.6だった。
とりあえず動かしてみる。 実行は
phpunit
で。
結果は
PHPUnit 9.5.6 by Sebastian Bergmann and contributors. Warning: Your XML configuration validates against a deprecated schema. Suggestion: Migrate your XML configuration using "--migrate-configuration"! .. 2 / 2 (100%) Time: 00:00.155, Memory: 18.00 MB OK (2 tests, 2 assertions)
何かOKでた。
デフォルトで何が動いている?
ここら辺が動いている模様。
app/tests/Feature/ExampleTest.php app/tests/Unit/ExampleTest.php
これらはlaravelにデフォルトでおかれているファイル。
動作させるフォルダやディレクトリの設定は
app/phpunit.xml
にある。
クラス名にTestついてなきゃだめ、とかそんなルールっぽいのが書いてる。
テストの作成
phpunitで動作させるクラスを作成する。 laravelでのコマンド
php artisan make:test HomeTest
上記コマンドではデフォルトでFeatureディレクトリにファイルを作成する。 --unitオプションでUnitディレクトリに作成。 FeatureとUnitの使い分けは、
- Featureは機能のテスト
- Unitはメソッドのテスト
のイメージかしら。 ここら辺の使い方は開発時にルールを決めた方がよさげ。
なお、クラス名は最後「Test」(ファイル名が◯◯Test.php)で作る必要あり。
テストクラスの実装
ログイン後にhomeへのリクエストが機能しているかを確認するためのテスト。 下記は、テストユーザを作って、そのユーザでログインし、認証されたユーザで正常にhomeのコンテンツが返されるか、を確認している。
<?php
namespace Tests\Feature;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithFaker;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Tests\TestCase;
use App;
/**
* テストデータ
*/
class TestData
{
public const email = 'user1@example.com';
public const password = 'Test1234';
}
/**
* ホームコントロールテスト
*/
class HomeTest extends TestCase
{
// データベースの初期化にトランザクションを使う
use DatabaseTransactions;
// ログインユーザの保持用
public $TestUser;
/**
* 初期設定
*
* @return void
*/
public function setUp(): void
{
parent::setUp();
// `users` テーブルにデータを作成
$this->TestUser = factory(App\User::class)->create([
'id' => '999',
'name' => 'test太郎',
'password' => bcrypt(TestData::password),
'email' => TestData::email,
]);
}
/**
* テストユーザでのログイン
*
* @return void
*/
public function Login()
{
// ログインページへの単純なアクセス
$response = $this->get(route('login'));
$response->assertStatus(200);
// ログイン実施
$response = $this->post(route('login'), [
'email' => TestData::email,
'password' => TestData::password,
]);
// リダイレクトでページ遷移するのでstatusは302
$response->assertStatus(302);
// リダイレクト先のパス
$response->assertRedirect('/home');
// ユーザーがログイン認証されているか
$this->assertAuthenticatedAs($this->TestUser);
}
/**
* ログインのテスト
*
* @return void
*/
public function testIndex()
{
// ログイン
$this->Login();
// ログイン後のhome
$response = $this->get(route('home'));
$response->assertStatus(200);
}
}
assertについて
望んだ値かをチェックするためメソッド。色んな種類があるので、状況に応じて使い分ける。
factoryについて
テストデータを作るもの。 ファイルは以下に置かれる。
database/factories
ちなみに、
php artisan ui vue –auth
上記のartisanコマンドでユーザ認証機能などを作成している場合、UserのFactoryはデフォルトで作成されている。
テスト実施時にpostのレスポンスコードが419
419エラーコードはCSRFでのエラーらしい。
テストの時は無視するように設定。
以下のファイルを開き、
App/Middleware/VerifyCsrfToken.php
以下のコードを追加。
public function handle($request, \Closure $next)
{
if (env('APP_ENV') !== 'testing') {
return parent::handle($request, $next);
}
return $next($request);
}
testingとかその辺の理由は
app/phpunit.xml
あたりを覗くとわかりそうな気がしないでもない