簡単だった。さすがLaravel。
テストの無かったアプリケーションに、テストを導入した。
まずはクリティカルなログインをカバーする。
実際にテストを書くよりも、環境作ったり、 Seeder
作ったりする過程の方が長かった。
最初から環境が整ってれば別だが・・・。
環境
- Laravel 5.1
- PHP 7.0.13
対象コード (一部)
普通のログインフォーム。
<form method="POST" action="{{ url('/auth/user-login') }}">
<input id="email" type="email" name="email" placeholder="">
<input id="password" type="password" name="password">
<button type="submit">ログイン</button>
</form>
// ログイン処理
public function userLogin(Request $request)
{
$credentials = $request->only('email', 'password');
if ($this->auth->attempt($credentials)) {
return redirect()->intended('/home');
}
}
Factory
適当なユーザーを作るやつ。これ便利だなー。
<?php
$factory->define(App\Models\User::class, function(Faker\Generator $faker) {
return [
'name' => $faker->name,
'email' => $faker->unique()->companyEmail,
'password' => bcrypt('secret'),
];
});
テストコード
すごく直感的。
DatabaseTransactions
トレイトにより、作成したユーザーは、メソッド終了と同時にロールバックされる。これも便利だなー。
<?php
namespace Tests\Integration;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use App\Models\User;
use Tests\TestCase;
class UserLoginTest extends TestCase
{
use DatabaseTransactions;
public function testUserLoginByEmail()
{
$user = factory(User::class, 'student')->create();
$this->visit('/login')
->type($user->email, 'email')
->type('secret', 'password')
->press('ログイン')
->seePageIs('/home');
}
}
<?php
abstract class TestCase extends BaseTestCase
{
public function createApplication()
{
// testing 環境でもlocal 環境を見に行ってしまうため
// キャッシュを読み込まないようにしている
if (file_exists(__DIR__.'/../bootstrap/cache/config.php'))
unlink(__DIR__.'/../bootstrap/cache/config.php');
}
}
abstract
にしておかないとPHPUnitがテストしようとしてエラーを吐く。
なお、 Tests\
という namespace
は標準で付いていないので、 composer.json
で PSR-4
オートローダーを設定する必要がある。
"psr-4": {
"App\\": "app/",
"Tests\\": "tests/"
}
[追記]
autoload-dev
に追加した方が良い。本番のパフォーマンスにわずかに影響するかも?
[/追記]
[さらに追記]
そもそも名前空間を指定しなくて良いという意見もある。指定しないと何となく不安になる、ディレクトリ構造とファイル名が対応しなくなるなどの弊害があるかもしれないが、そもそも PHPUnit がファイルを探してテストを実行するので、オートロードする必要も無い。
[/さらに追記]
実行
......
Time: 2.15 seconds, Memory: 22.00MB
OK (1 tests, 5 assertions)
成功すると気分がいいですね。