0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

laravelのテスト、始め方、完全版

Last updated at Posted at 2024-07-02

この記事は、Laravel Framework 10.7.1で動作確認しています。

今やってるlaravelの開発もほぼ目処がついたところでそろそろテストでも書くかなと思って、調べてみたら、案の定ろくな情報がない。
まあ、テスト大事だよね、と言いつつ、誰もテストなんて書いていないという実態、というところではないですかね。
ちなみに真っ先にchatGpt様にお伺いしてみたが、ものの見事に動かないソースを紹介されました。

・・・ということで始めよう。テストね、うかつにchatGpt様のソースなんぞを実行すると、DBを空っぽにされてしまうので注意しよう(爆。
つまり、テストはDBを使うのでテスト用のDBを用意する必要があるのだ。

実に面倒である。
当初はもうホントにミニマムな開発でマイグレーションとか必要ないかなと思っていたが、こうなるとホイホイDBを作れた方が楽である。マイグレーションを設定しよう。まずはコマンドラインから、

php artisan make:migration create_customers_table --table=customers

make:migrationする。そうすると、database/migrationsの下に2023_04_17_033534_create_customers_table.php というようなファイルが作られる。これを見本として修正していけばよい。

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration {
    /**
     * Run the migrations.
     */
    public function up(): void
    {
        Schema::create('customers', function (Blueprint $table) {
            $table->id();
            $table->integer('customer_number')->comment('お客様No');
            $table->string('name')->comment('会社名');
            $table->string('yomi')->nullable()->comment('よみがな');
            $table->integer('status')->default(0)->comment('状態');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     */
    public function down(): void
    {
        Schema::drop('customers');
    }
};

こんな感じだ。
up() にクリエイトテーブル、down() にドロップテーブル。
id() とtimestamps() は自動で設定してくれる。
(idは主キーでオートインクリメント、timestampsは登録日時と更新日時)
他のカラムは、何も指定しないと全部 not null が指定されてしまうので、->nullable() をくっつける。

こういうのをテーブルの数だけ作る。
作り終わったら、コマンドから、

php artisan migrate

とすればよい。
一気にテーブルが生成される。

あと、テーブルに初期値を入れることもあるだろう。最初の管理者ユーザーとか、消費税率とか、そういうのは /database/seeders/DatabaseSeeder.php に書いておく。
以下は消費税率の例。

    public function run(): void
    {
        DB::table('tax_rates')->insert([
            'start_date' => '2019-10-01',
            'end_date' => '2099-12-31',
            'tax_rate' => 0.1,
        ]);
    }

出来たら以下のコマンドでインサートされる。

php artisan db:seed

テスト環境についても同様で、テスト用のDBを作ったら、.envファイルをコピーして .env.testing を作る。

.env.testing
DB_CONNECTION=mysql
DB_HOST=loalhost
DB_PORT=3306
DB_DATABASE=test_my_db
DB_USERNAME=my_user
DB_PASSWORD=password

DB_DATABASE のところをテスト用DBの名前に変更する。

あとAPP_KEY というのがあるので、以下のコマンドを打って更新しておく。

php artisan key:generate --env=testing

次に直下の phpunit.xml を編集する。

phpunit.xml
        <env name="DB_CONNECTION" value="mysql"/>
        <env name="DB_DATABASE" value="test_my_db"/>

おそらくこの2行、コメントアウトされているので、コメントを外して、それぞれvalueを書き換える。
テスト用DBにマイグレイトしておく。

php artisan migrate --env=testing

最後にコマンドで、

php artisan config:clear

これで、キャッシュされた設定ファイルが削除され、アプリケーションが再起動される。やっておかないと、実際のDBの方にバンバン書き込まれる。

ついでなのでここでFactoryも作っておこう。
これはテスト時にダミーデータを生成するために使用される。

<?php

namespace Database\Factories;

use Illuminate\Database\Eloquent\Factories\Factory;

/**
 * @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Customer>
 */
class CustomerFactory extends Factory
{
    /**
     * Define the model's default state.
     *
     * @return array<string, mixed>
     */
    public function definition(): array
    {
        return [
            //
            'customer_number' => fake()->randomDigit(),
            'name' => fake()->name(),
        ];
    }
}

で、後はテストを書けばよい。まずはコマンドでひな型を作って、

php artisan make:test CustomerControllerTest

こんなソースが作られるので、

<?php

namespace Tests\Feature;

use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithFaker;
use Tests\TestCase;

class CustomerControllerTest extends TestCase
{
    /**
     * A basic feature test example.
     */
    public function test_example(): void
    {
        $response = $this->get('/');

        $response->assertStatus(200);
    }
}

自分の考えるテストを追加していく。

public function testGetIndex(): void
    {
        $response = $this->get('/customer');

        $response->assertSee('顧客一覧');
        $response->assertOk();
        $response->assertStatus(200);
        $response->assertViewIs('customers.index');
    }

出来たら以下のコマンドでテストを実行する。

php artisan test .\tests\Feature\CustomerControllerTest.php

実際のところ、これは管理者画面なので、ログイン認証済みのセッションを持っていないとログイン画面にリダイレクトで戻されてしまう。
そうするとassertStatus(200)のはずが302を返すので一生合格しない。

そういう場合はresponse getのところにsession を挟む。

$response = $this->withSession(['account' => '管理者'])->get(route('customer'));

あとデータベースへのインサートのテストは、

public function testInsertSuccess()
    {
        $customer = new Customer();
        $customer->customer_number = "1012";
        $customer->name = "株式会社バーベキュー";
        $result = $customer->save();
        $this->assertTrue($result);
    }

こんな感じでオッケーだ。

新規登録メソッドのテストはこんな感じで

public function testStore()
    {
        $customerData = [
            'customer_number' => '1026',
            'name' => 'テスト太郎',
        ];

        $response = $this->post('/customer/store', $customerData);
        $response->assertRedirect(route('customer'));

        $this->assertDatabaseHas('customers', $customerData);
    }

編集の更新処理は、こんな感じで。ここでFactoryが登場する。

public function testUpdate()
    {
        $customer = Customer::factory()->create();
        $updatedData = [
            'id' => $customer->id,
            'customer_number' => '2000';,
            'name' => 'テスト次郎',
        ];

        $response = $this->post('/customer/update/', $updatedData);

        $response->assertRedirect(route('customer'));
        $this->assertDatabaseHas('customers', $updatedData);
    }

テストが終ったらDBをクリアしてくれる設定にしたい場合は、以下のようにRefreshDatabaseをuseしておけばよい。

<?php

namespace Tests\Feature;

use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
use App\Models\Customer;

class CustomerControllerTest extends TestCase
{
    use RefreshDatabase;

以上、最初から計画的に、migration、 seed、 factoryといったDB系の設定ファイルを整備して、テストを書きつつ、コントローラを埋めていく、というのが理想的だろう。

テーブルが多いと気が遠くなるような作業だろうが。

0
1
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?