Laravelテスト②掲示板投稿テストと詰まったところ

テスト

php unit テストの勉強を久しぶりに。。

  • 既存のユーザーを使って
  • 掲示板の投稿ページからpost 送信をして
  • 掲示板一覧ページに戻る

この一連の流れをテストしてみましょう!

バージョン:laravel6.8

参考にしたのはやんばるさんのブログ。いつもありがとうございます!

テスト用ファイルを作成

まずはコードを書くファイルを作成。

php artisan make:test PostTest

というコマンドでFeature配下にテスト用のファイルができます。

php artisan make:test PostTest --unit

これでUnit配下に作成されます。

詰まったとこ

use PHPUnit\Framework\TestCaseとは

最初あまり考えずにUnit配下にファイルを作成して書いていたのですが、最小構成のテストでもエラーになる。

しかも、書き方が悪いというよりも根本的に間違っているような。。なんで??としばらく詰まってしまったのですが、

ファイルでuseしている記述を変えたらうまくいきました。

 use PHPUnit\Framework\TestCase;  //これをやめて
 use Tests\TestCase; //こっちを使う

でも use PHPUnit\Framework\TestCase ってファイル作成時から書いてあったのに・・・なんであかんの??

と調べたところ、

  • use PHPUnit\Framework\TestCase ・・・ご本家phpのクラス
  • use Tests\TestCase ・・・Laravelの機能を絡めて使うことができる拡張クラス(??)

なんて書けばいいのか難しいですが、とにかくLaravelが用意している機能を絡めて使うには後者をuseしなければいけない、ということです。

最初からFeature配下にファイルを作っていれば use Tests\TestCase が記述されていたのに、私がUnitに作ったからこうなったというオチでした。

phpご本家のサイト

laravel6で提供されているテストメソッド(の一部)

データベースを指定する

テストコードの中で既存ユーザーとしてログインさせたい・・のに「そんなユーザーいないよ!」というエラーが出ました。

DBを確認してもちゃんと存在するし、ユーザーを変えてみてもダメ。。

なんで〜と思ってぐぐったところ、テストの場合phpunit.xmlというファイル(Laravelルートにあります)を触る必要があるようです。

私の場合DBがmysqlではない別のDBを見る指定になっていたため起こったエラーでした。

テスト用コード

/** * A basic unit test example. 
* * @test 
*/ 
public function 掲示板に投稿処理() {
$this 
->actingAs(User::find(1)) 
->get('/posts');

$this->withoutExceptionHandling(); 

$response = $this->withoutMiddleware()
->post('/posts' ,[
 'title' => 'テストタイトル', 
'content' => 'テスト投稿' ]);

$response->assertRedirect('/posts');

 }

ポイント

  • @testと書けばメソッド名にtest…を付けなくても良い
  • テスト名は日本語でもいい
  • 仕様上掲示板に投稿できるのはログインユーザーのみだったので、テストの際もログインユーザーを作る必要がある
  • factoryを使ってログインユーザーを作成してもいいが、今回はひとまず既存ユーザーで代用
  • $this->withoutExceptionHandling(); を書いておくと、エラー時にlogファイルではなくターミナルに表示されるので手間が省ける

テスト実行

テストを実行する際は、

vendor/bin/phpunit

とターミナルに入力するとテストが動きます。ただ全てのテストが動いてしまうので、動かしたいテストファイルを指定するなら

vendor/bin/phpunit ./tests/Unit/ExampleTest.php

のように指定すると良い。

テストの関数を指定して実行する場合

vendor/bin/phpunit --filter 関数名

これでOK。

実行すると

OKが出ました!

おまけ:ダミーユーザーを作成して実行

今回は簡単にするために既存ユーザーを使ってログインしましたが、既存のデータをむやみに使うのもあれなので

実際にはfactoryを使ったりするようです。

database/factories/UserFactory.php にて

$factory->define(User::class, function (Faker $faker) { 
return [
 'name' => $faker->name,
 'email' => $faker->unique()->safeEmail, 
'email_verified_at' => now(), 
'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password
'remember_token' => Str::random(10), ];
}
);

こんな風にダミーユーザーを作る用意をしておく。

そして先ほどのテストコードを一部だけ変更

    public function 掲示板に投稿処理()
    {
        $user = factory(User::class)->create();  //ここでダミーユーザー作成

        $this
            ->actingAs($user) //ダミーユーザーでログイン
            ->get('/posts');

        
        $this->withoutExceptionHandling();
        $response = $this->withoutMiddleware()->post('/posts' ,[
            'title' => 'テストタイトル',
            'content' => 'テスト投稿'
        ]);

        $response->assertRedirect('/posts');
    }

これで、既存ユーザーを使わずテストできました!

DBを汚さないために

上記テストを実行すると、DBに実際にデータが挿入されます。

テストの度にデータが増えるのを防ぐために、以下を追記します。

use Illuminate\Foundation\Testing\DatabaseTransactions;

こちらをテストファイルに追記して、テストクラス内で

use DatabaseTransactions;

のようにすると、DBのデータは増えずテストだけが実行されます!

タイトルとURLをコピーしました