Laravelアプリケーションでモデルファクトリーを使用するにはどうすればよいですか?

青灯夜游
リリース: 2022-11-28 20:26:22
転載
1170 人が閲覧しました

Laravel アプリケーションでモデル ファクトリを使用するにはどうすればよいですか?以下の記事では、Laravel モデルエンジニアリングをテストに活用する方法を紹介しますので、ご参考になれば幸いです。

Laravelアプリケーションでモデルファクトリーを使用するにはどうすればよいですか?

#Laravel Model Factory は、アプリケーションのテスト中に使用できる最高の機能の 1 つです。これらは、予測可能で簡単に複製可能なデータを定義する方法を提供し、テストの一貫性と制御性を維持します。

簡単な例から始めましょう。ブログ用のアプリケーションがあるので、当然、公開済み、下書き済み、またはキュー済みのステータスを持つ Post モデルがあります。この例の Eloquent モデルを見てみましょう:

declare(strict_types=1);

namespace App\Models;

use App\Publishing\Enums\PostStatus;
use Illuminate\Database\Model;

class Post extends Model
{
    protected $fillable = [
        'title',
        'slug',
        'content',
        'status',
        'published_at',
    ];

    protected $casts = [
        'status' => PostStatus::class,
        'published_at' => 'datetime',
    ];
}
ログイン後にコピー

ここでわかるように、ステータス列の列挙型があり、これから設計します。ここで列挙型を使用すると、プレーンな文字列、ブール型フラグ、または紛らわしいデータベース列挙型の代わりに、PHP 8.1 の機能を利用できるようになります。

 declare(strict_types=1);

namespace App\Publishing\Enums;

enum PostStatus: string
{
    case PUBLISHED = 'published';
    case DRAFT = 'draft';
    case QUEUED = 'queued';
}
ログイン後にコピー

さて、ここで議論しているトピック、Model Factory に戻りましょう。単純なファクトリは単純に見えます:

 declare(strict_types=1);

namespace Database\Factories;

use App\Models\Post;
use App\Publishing\Enums\PostStatus;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Arr;
use Illuminate\Support\Str;

class PostFactory extends Factory
{
    protected $model = Post::class;

    public function definition(): array
    {
        $title = $this->faker->sentence();
        $status = Arr::random(PostStatus::cases());

        return [
            'title' => $title,
            'slug' => Str::slug($title),
            'content' => $this->faker->paragraph(),
            'status' => $status->value,
            'published_at' => $status === PostStatus::PUBLISHED
                ? now()
                : null,
        ];
    }
}
ログイン後にコピー

したがって、テストではポスト ファクトリをすぐに呼び出してポストを作成できるようになりました。これをどのように行うかを見てみましょう:

 it('can update a post', function () {
    $post = Post::factory()->create();

    putJson(
        route('api.posts.update', $post->slug),
        ['content' => 'test content',
    )->assertSuccessful();

    expect(
        $post->refresh()
    )->content->toEqual('test content');
});
ログイン後にコピー
ログイン後にコピー

十分に単純なテストですが、ビジネス ルールで投稿タイプに基づいて特定の列のみを更新できると規定されている場合はどうなるでしょうか?テストをリファクタリングして、これを確実に実行できるようにしましょう:

it('can update a post', function () {
    $post = Post::factory()->create([
        'type' => PostStatus::DRAFT->value,
    ]);

    putJson(
        route('api.posts.update', $post->slug),
        ['content' => 'test content',
    )->assertSuccessful();

    expect(
        $post->refresh()
    )->content->toEqual('test content');
});
ログイン後にコピー

完璧に、create メソッドにパラメータを渡して、作成時に正しい型を設定できるようにすることで、ビジネス ルールが成功するようにすることができます。文句を言わないでください。しかし、このように書くのは少し面倒なので、ファクトリを少しリファクタリングして、ステータスを変更するメソッドを追加しましょう:

 declare(strict_types=1);

namespace Database\Factories;

use App\Models\Post;
use App\Publishing\Enums\PostStatus;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Str;

class PostFactory extends Factory
{
    protected $model = Post::class;

    public function definition(): array
    {
        $title = $this->faker->sentence();

        return [
            'title' => $title,
            'slug' => Str::slug($title),
            'content' => $this->faker->paragraph(),
            'status' => PostStatus::DRAFT->value,
            'published_at' => null,
        ];
    }

    public function published(): static
    {
        return $this->state(
            fn (array $attributes): array => [
                'status' => PostStatus::PUBLISHED->value,
                'published_at' => now(),
            ],
        );
    }
}
ログイン後にコピー

新しく作成された投稿がすべて下書きになるように、ファクトリのデフォルト値を設定します。次に、状態を公開するように設定するメソッドを追加します。これにより、正しい Enum 値が使用され、公開日が設定されます。これにより、テスト環境でより予測可能で再現可能になります。テストがどのようになるかを見てみましょう:

 it('can update a post', function () {
    $post = Post::factory()->create();

    putJson(
        route('api.posts.update', $post->slug),
        ['content' => 'test content',
    )->assertSuccessful();

    expect(
        $post->refresh()
    )->content->toEqual('test content');
});
ログイン後にコピー
ログイン後にコピー

単純なテストに戻ります。つまり、下書き投稿を作成するテストが複数ある場合は、ファクトリを使用できます。次に、公開された状態のテストを作成して、エラーがあるかどうかを確認しましょう。

 it('returns an error when trying to update a published post', function () {
    $post = Post::factory()->published()->create();

    putJson(
        route('api.posts.update', $post->slug),
        ['content' => 'test content',
    )->assertStatus(Http::UNPROCESSABLE_ENTITY());

    expect(
        $post->refresh()
    )->content->toEqual($post->content);
});
ログイン後にコピー

今回は、公開された投稿を更新しようとしたときに検証エラー ステータスを受け取るかどうかをテストします。これにより、コンテンツが保護され、アプリケーション内で特定のワークフローが強制されることが保証されます。

それでは、工場内の特定のコンテンツも保証したい場合はどうなるでしょうか?必要に応じて、ステータスを変更する別のメソッドを追加できます:

 declare(strict_types=1);

namespace Database\Factories;

use App\Models\Post;
use App\Publishing\Enums\PostStatus;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Str;

class PostFactory extends Factory
{
    protected $model = Post::class;

    public function definition(): array
    {
        return [
            'title' => $title = $this->faker->sentence(),
            'slug' => Str::slug($title),
            'content' => $this->faker->paragraph(),
            'status' => PostStatus::DRAFT->value,
            'published_at' => null,
        ];
    }

    public function published(): static
    {
        return $this->state(
            fn (array $attributes): array => [
                'status' => PostStatus::PUBLISHED->value,
                'published_at' => now(),
            ],
        );
    }

    public function title(string $title): static
    {
        return $this->state(
            fn (array $attributes): array => [
                'title' => $title,
                'slug' => Str::slug($title),
            ],
        );
    }
}
ログイン後にコピー

そこで、テスト内で、API 経由で下書きの投稿タイトルを更新できることを確認するための新しいテストを作成できます:

 it('can update a draft posts title', function () {
    $post = Post::factory()->title('test')->create();

    putJson(
        route('api.posts.update', $post->slug),
        ['title' => 'new title',
    )->assertSuccessful();

    expect(
        $post->refresh()
    )->title->toEqual('new title')->slug->toEqual('new-title');
});
ログイン後にコピー

そのため、工場出荷時の状態をうまく使用してテスト環境での制御を行うことができ、可能な限り多くの制御を行うことができます。そうすることで、テストの準備を一貫して行うことができ、特定の時点でのアプリケーションの状態が適切に反映されるようになります。

テスト用に多数のモデルを作成する必要がある場合はどうすればよいでしょうか?私たちは何をすべきか?簡単な答えは、ファクトリーに次のように伝えることです:

it('lists all posts', function () {
    Post::factory(12)->create();

    getJson(
        route('api.posts.index'),
    )->assertOk()->assertJson(fn (AssertableJson $json) =>
        $json->has(12)->etc(),
    );
});
ログイン後にコピー

したがって、12 個の新しい投稿を作成し、インデックス ルートを取得したときに 12 個の投稿が返されるようにします。 count をファクトリ メソッドに渡す代わりに、count メソッドを使用することもできます。

Post::factory()->count(12)->create();
ログイン後にコピー

ただし、アプリケーションでは、特定の順序で実行したい場合があります。最初のものをドラフトにし、2 番目のものを公開したいとしますか?

 it('shows the correct status for the posts', function () {
    Post::factory()
        ->count(2)
        ->state(new Sequence(
            ['status' => PostStatus::DRAFT->value],
            ['status' => PostStatus::PUBLISHED->value],
        ))->create();

    getJson(
        route('api.posts.index'),
    )->assertOk()->assertJson(fn (AssertableJson $json) =>
        $json->where('id', 1)
            ->where('status' PostStatus::DRAFT->value)
            ->etc();
    )->assertJson(fn (AssertableJson $json) =>
        $json->where('id', 2)
            ->where('status' PostStatus::PUBLISHED->value)
            ->etc();
    );
});
ログイン後にコピー

アプリケーションでモデル ファクトリをどのように使用しますか?何か素敵な使い方は見つかりましたか?ツイッターで教えてください!

元のアドレス: https://laravel-news.com/laravel-model-factories

翻訳アドレス: https://learnku.com/laravel/t/70290

#[関連する推奨事項:

laravel ビデオチュートリアル]

以上がLaravelアプリケーションでモデルファクトリーを使用するにはどうすればよいですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
ソース:learnku.com
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート