こんにちわ、PHPエンジニアのエンジニア婦人(@naho_osada)です。
PHPエンジニアとして9年~の経験があります。
ここではLaravelでログイン画面を作り、phpunitの試験を実装するまでの流れを書いています。
※CentOS7 LAMP環境で行っています。
※MariaDB、Laravelそのもののインストール(含むComposer)、Nodejsがインストールされている前提です。
これらのインストール手順はこちらです。
- Hyper-V LAMP環境を構築-2-3.MariaDBとphpMyAdminを入れよう
- Hyper-V LAMP環境を構築-3.Laravelをインストール
- CentOS7に新しいnodejsをインストールする
ログイン画面を作る
公式の「認証」ページに書いてあるコマンドを実行します。
composer require laravel/ui
php artisan ui vue --auth
npm install && npm run dev
これで基本的なログイン機能ができました!なんて便利なんでしょう…
ログイン画面を表示できます。ログイン処理はまだできません。
データベースとテーブルを作る
画面はできましたが、まだデータベースとの連携ができていません。必要な情報を入力してmigrateします。
データベースのユーザー、パスワード、データベースを作成しておきます。ユーザーのホストは「localhost」(ユーザー名’@’localhost)です。
.envファイルを編集する
laravelの.envファイルを開いて、データベース接続情報を入力します。
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=データベース名
DB_USERNAME=データベースのユーザー名
DB_PASSWORD=データベースのパスワード
設定後、コンソールからmigrateします。
php artisan migrate
失敗するときはエラーメッセージが出るので、それをよく読んで解決します。大体ユーザー名やパスワードが違ってログインできない、データベースがないなどが多いかと思います。
migrateからユーザー、パスワードを設定する
/database/migrationsに
- 2014_10_12_000000_create_users_table.php
- 2014_10_12_100000_create_password_resets_table.php
- 2019_08_19_000000_create_failed_jobs_table.php
の3ファイルができています。1番目の「2014_10_12_000000_create_users_table.php」を修正します。
up関数の中でテーブルの情報を定義しています。
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('email')->unique();
$table->timestamp('email_verified_at')->nullable();
$table->string('password');
$table->rememberToken();
$table->timestamps();
});
}
これを以下のように変更します。
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->char('name', 50); // char(50)
$table->char('email', 250)->unique(); // char(250)
$table->timestamp('email_verified_at')->nullable();
$table->string('password');
$table->rememberToken();
$table->timestamps();
});
// ユーザーを追加
DB::table('users')->insert([
'name' => 'test',
'email' => 'xxxxx@gmail.com',
'password' => Hash::make('test'),
]);
DB::table('users')->insert([
'name' => 'test02',
'email' => 'xxxxx@gmail.com',
'password' => Hash::make('test02'),
]);
}
データベースの名前とメールアドレスをchar型にしました。
同時にユーザーテーブルにテストデータを格納するようにしました。
もう一度migrateしてみます。一旦ロールバック(1つ前に戻す)してからmigrateです。
php artisan migrate:rollback
php artisan migrate
データベースをphpMyAdminなどで確認すると、指定したデータが格納されていることがわかります。
ログインしてみる
いよいよログインしてみます。ログイン画面(/login)にアクセスします。
設定したメールアドレスとパスワードを入れて、ダッシュボードに来たら成功です。
エラーが出た場合
「Access denied for user root@localhost」などと表示されることがあります。ユーザーが.envファイルで指定しているものと異なる場合、変更が反映されていない可能性があります。
この場合、「php artisan serve」でLaravelを再起動、または「php artisan cache:clear」でキャッシュをクリアすると解決します。
ログインテスト(PHP Unit)を書いて実行する
Laravelのコマンドで生成したものを確認するテストを書いてみます。
作ったログイン機能が正常に動作するかを確認する試験を書いてみます。LaravelはPHPUnitが同梱されているので、特別インストールする必要はありません。
テスト用の.env.testingファイルを作成する
実データでテストするよりも、テスト用のデータを使ってテストする方が安全です。万一テストでデータ破壊してしまったら…元に戻せなくなったら…考えたら恐ろしいですね。テスト用のデータベースを使用します。
テスト用のデータベースを作成し、それを指定してテスト実行時はこちらを見るようにします。
phpunit.xmlの<php></php>内にある「server name=”APP_ENV”」のvalueはデフォルトで「testing」になっています。
.envファイルはこれが「.env.testing」を参照します。なければ.envを見ます。
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=テスト用のデータベース名
DB_USERNAME=テスト用のデータベースのユーザー名
DB_PASSWORD=テスト用のデータベースのパスワード
テストファイルの作成
php artisan make:test テストクラス名
# Unitテストの場合は php artisan make:test テストクラス名 --unitを実行
実行すると以下のファイルが「/tests/Feature」内にできます。ここではクラス名をLoginにしてみました。
<?php
namespace Tests\Feature;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithFaker;
use Tests\TestCase;
class Login extends TestCase
{
/**
* A basic feature test example.
*
* @return void
*/
public function testExample()
{
$response = $this->get('/');
$response->assertStatus(200);
}
}
FeatureとUnitの違い
FeatureはURL単位の一連の動作、unitは関数単位の試験を書いて使い分けるようです。
ログインのテストを書く
一例を載せておきます。ざっと説明すると
- ログイン画面を表示→表示ができること、認証されていないこと
- 直接ダッシュボードにアクセス→ログイン画面へリダイレクト、認証されていないこと
- ログイン処理→処理後、認証されていること
- ログアウト→ログイン後、ログアウト処理が実行されて認証されていないこと
を確認しています。
<?php
namespace Tests\Feature;
use App\User;
use Illuminate\Foundation\Testing\WithFaker;
use Tests\TestCase;
use DatabaseMigrations; // テスト用データベースを使用
use Illuminate\Foundation\Testing\RefreshDatabase; // テスト用データを自動で元に戻す
class LoginTest extends TestCase
{
use RefreshDatabase;
/**
* ログイン画面を表示
*/
public function testLoginView()
{
$response = $this->get('/login');
$response->assertStatus(200);
// 認証されていないことを確認
$this->assertGuest();
}
/**
* ダッシュボードアクセス(ログイン画面へリダイレクト)
*/
public function testNonloginAccess()
{
$response = $this->get('/home');
$response->assertStatus(302)
->assertRedirect('/login'); // リダイレクト先を確認
// 認証されていないことを確認
$this->assertGuest();
}
/**
* ログイン処理を実行
*/
public function testLogin()
{
// 認証されていないことを確認
$this->assertGuest();
// ダミーログイン
$response = $this->dummyLogin();
$response->assertStatus(200);
// 認証を確認
$this->assertAuthenticated();
}
/**
* ログアウト処理を実行
*/
public function testLogout()
{
// ダミーログイン
$response = $this->dummyLogin();
// 認証を確認
$this->assertAuthenticated();
$response = $this->post('/logout');
// ホーム画面にリダイレクト
$response->assertStatus(302)
->assertRedirect('/'); // リダイレクト先を確認
// 認証されていないことを確認
$this->assertGuest();
}
/**
* ダミーユーザーログイン
*/
private function dummyLogin()
{
$user = factory(User::class, 'default')->create();
return $this->actingAs($user)
->withSession(['user_id' => $user->id])
->get(route('home')); // homeにリダイレクト
}
}
テストを実行する
laravelプロジェクトフォルダで実行します。
./vendor/bin/phpunit
# 上記のテストコードを実行すると以下のように返ってきます。
PHPUnit 8.5.8 by Sebastian Bergmann and contributors.
.... 4 / 4 (100%)
Time: 638 ms, Memory: 28.00 MB
OK (4 tests, 14 assertions)
まとめ
今回はLaravelのコマンドから管理画面を作成し、その動作を確認するPHPUnitのテストコードを書きました。
実際のテスト駆動開発の場合はPHPUnitから書いて実装していくことになりますが、今回は「Laravelのコマンドで生成したものを確認するテストを書いてみる」ということで順序が逆になっています。
まずはこうやって動くんだ!という体感を得たいときに、試してみてください(‘ω’)ノ