首頁 > php框架 > Laravel > 主體

如何在Laravel應用程式中使用模型工廠?

青灯夜游
發布: 2022-11-28 20:26:22
轉載
1150 人瀏覽過

如何在Laravel應用程式中使用模型工廠?以下這篇文章為大家介紹一下在測試中使用 Laravel 模型工程的方法,希望對大家有幫助!

如何在Laravel應用程式中使用模型工廠?

Laravel 模型工廠是你可以在應用程式中進行測試時使用的最佳功能之一。它們提供了一種定義可預測且易於複製的資料的方法,以便您的測試保持一致和可控。

讓我們從一個簡單的例子開始。我們有一個用於寫部落格的應用程序,所以很自然地,我們有一個 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',
    ];
}
登入後複製

正如你在此處看到的,我們有一個用於狀態列的 Enum,我們現在將對其進行設計。這裡使用枚舉允許我們利用 PHP 8.1 的特性,而不是純字串、布林標誌或混亂的資料庫枚舉。

 declare(strict_types=1);

namespace App\Publishing\Enums;

enum PostStatus: string
{
    case PUBLISHED = 'published';
    case DRAFT = 'draft';
    case QUEUED = 'queued';
}
登入後複製

現在,讓我們回到我們在這裡討論的主題:模型工廠。一個簡單的工廠看起來很簡單:

 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,
        ];
    }
}
登入後複製

所以在我們的測試中,我們現在可以快速調用我們的 post factory 為我們建立一個 post。讓我們看看我們可以如何做到這一點:

 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();
登入後複製

但是,在我們的應用程式中,有時我們可能希望以特定順序運行事物。假設我們希望第一個是草稿,但第二個已發布?

 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();
    );
});
登入後複製

你如何在應用程式中使用模型工廠?你有沒有找到任何很酷的方法來使用它們?在 twitter 上告訴我們!

原文網址:https://laravel-news.com/laravel-model-factories

翻譯網址:https://learnku.com/laravel/t/70290

【相關推薦:laravel影片教學

以上是如何在Laravel應用程式中使用模型工廠?的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:learnku.com
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板
關於我們 免責聲明 Sitemap
PHP中文網:公益線上PHP培訓,幫助PHP學習者快速成長!