LoginSignup
0
0

Factoryクラスに何も書かなくてもいいケース

Posted at

はじめに

Laravelでテストを実装中に「Class "Database\Factories\MessageRoomFactory" not found」というエラーに遭遇しました。

今回は、database/factoriesに新しくMessageRoomFactoryクラスを作成することで対処ができました。」

環境

Laravel 9.52.16

問題

  • 次のようなテストを実行したい
MessagesControllerTest.php(該当メソッドのみ)
public function test_Messages_store()
    {
        // テストユーザを作成
        $user = User::factory()->create();
        // メッセージルームを作成
        $message_room = MessageRoom::factory()->create();

        // テスト用のフォームデータを作成
        $formData = [
            'message' => 'テストメッセージ',
        ];

        // 作成したユーザでアクセス
        $response = $this->actingAs($user)->post('/my/messages/store/' . $message_room->id, $formData);

        $response->assertStatus(302);
        $this->assertDatabaseHas('messages', [
            'message' => $formData['message'],
            'message_room_id' => $message_room->id,
            'user_id' => $user->id,
        ]);


    }
  • しかし実行すると次のようなエラーが出る
root@:/var/www/html/niches# php artisan test --filter MessagesControllerTest      

Deprecated: PHP Startup: Use of mbstring.internal_encoding is deprecated in Unknown on line 0

Deprecated: PHP Startup: Use of mbstring.internal_encoding is deprecated in Unknown on line 0

   FAIL  Tests\Feature\Http\Controllers\MessagesControllerTest
   
   messages store

  ---

   Tests\Feature\Http\Controllers\MessagesControllerTest > messages store
   PHPUnit\Framework\ExceptionWrapper 

  Class "Database\Factories\MessageRoomFactory" not found

  at vendor/laravel/framework/src/Illuminate/Database/Eloquent/Factories/Factory.php:821
    817     public static function factoryForModel(string $modelName)
    818     {
    819         $factory = static::resolveFactoryName($modelName);
    820
   821         return $factory::new();
    822     }
    823
    824     /**
    825      * Specify the callback that should be invoked to guess factory names based on dynamic relationship names.


  Tests:  1 failed
  Time:   15.79s

「クラス"Database\Factories\MessageRoomFactory"が見つかりません」とのこと。

解決法

  • database/factoriesを確認してみると、確かにMesssageRoomFactoryがなかった
  • これにより、テストレコードを作成するためのfactory()メソッドが使えなかったっぽい
  • database/factoriesにMessageRoomFactoryクラスを追加する
database/factories/MessageRoomFactory.php
<?php

namespace Database\Factories;

use Illuminate\Database\Eloquent\Factories\Factory;

/**
 * @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\MessageRoom>
 */
class MessageRoomFactory extends Factory
{
    /**
     * Define the model's default state.
     *
     * @return array<string, mixed>
     */

    public function definition()
    {
        return [
            
        ];
    }
}
root@:/var/www/html/niches# php artisan test --filter MessagesControllerTest

Deprecated: PHP Startup: Use of mbstring.internal_encoding is deprecated in Unknown on line 0

Deprecated: PHP Startup: Use of mbstring.internal_encoding is deprecated in Unknown on line 0

   PASS  Tests\Feature\Http\Controllers\MessagesControllerTest

   messages store

  Tests:  1 passed
  Time:   12.13s

これで無事解決です!

補足

通常、Factoryにはテスト用のデフォルト値を設定しなければいけません。

しかし今回はテーブルが'id'、'timestamps'のみであり、Eloquentが勝手に補完してくれるので、空でも問題ありません。

mysql> desc message_rooms;
+------------+-----------------+------+-----+---------+----------------+
| Field      | Type            | Null | Key | Default | Extra          |
+------------+-----------------+------+-----+---------+----------------+
| id         | bigint unsigned | NO   | PRI | NULL    | auto_increment |
| created_at | timestamp       | YES  |     | NULL    |                |
| updated_at | timestamp       | YES  |     | NULL    |                |
+------------+-----------------+------+-----+---------+----------------+
3 rows in set (0.00 sec)

まず、主キーである'id'カラムは自動インクリメントにより値を指定する必要がありません。

また、'created_at'と'updated_at'はEloquentモデルが自動的に埋めてくれます。

よって今回のケースでは、フィールドを定義する必要がありません。

database/factories/MessageRoomFactory.php
<?php

namespace Database\Factories;

use Illuminate\Database\Eloquent\Factories\Factory;

/**
 * @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\MessageRoom>
 */
class MessageRoomFactory extends Factory
{
    /**
     * Define the model's default state.
     *
     * @return array<string, mixed>
     */

    public function definition()
    {
        // 今回はフィールドを定義する必要はなし
        return [
            
        ];
    }
}

おわりに

なんとなくFactoryクラスはモデルとセットで生成されると勘違いしていましたが、どうやら違うようでした。

やはりテストをする時にはFactoryクラスを使うのが便利ですね!

参考

0
0
0

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
0