溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Laravel應(yīng)用程序中怎么使用模型工廠

發(fā)布時(shí)間:2022-11-29 09:09:10 來源:億速云 閱讀:146 作者:iii 欄目:編程語言

本文小編為大家詳細(xì)介紹“Laravel應(yīng)用程序中怎么使用模型工廠”,內(nèi)容詳細(xì),步驟清晰,細(xì)節(jié)處理妥當(dāng),希望這篇“Laravel應(yīng)用程序中怎么使用模型工廠”文章能幫助大家解決疑惑,下面跟著小編的思路慢慢深入,一起來學(xué)習(xí)新知識(shí)吧。

Laravel 模型工廠是你可以在應(yīng)用程序中進(jìn)行測(cè)試時(shí)使用的最佳功能之一。它們提供了一種定義可預(yù)測(cè)且易于復(fù)制的數(shù)據(jù)的方法,以便你的測(cè)試保持一致和可控。

讓我們從一個(gè)簡(jiǎn)單的例子開始。我們有一個(gè)用于寫博客的應(yīng)用程序,所以很自然地,我們有一個(gè) Post 模型,該模型具有發(fā)布、起草或排隊(duì)的狀態(tài)。讓我們看一下這個(gè)例子的 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',
    ];
}

正如你在此處看到的,我們有一個(gè)用于狀態(tài)列的 Enum,我們現(xiàn)在將對(duì)其進(jìn)行設(shè)計(jì)。在這里使用枚舉允許我們利用 PHP 8.1 的特性,而不是純字符串、布爾標(biāo)志或混亂的數(shù)據(jù)庫枚舉。

 declare(strict_types=1);

namespace App\Publishing\Enums;

enum PostStatus: string
{
    case PUBLISHED = 'published';
    case DRAFT = 'draft';
    case QUEUED = 'queued';
}

現(xiàn)在,讓我們回到我們?cè)谶@里討論的主題:模型工廠。一個(gè)簡(jiǎn)單的工廠看起來很簡(jiǎn)單:

 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,
        ];
    }
}

所以在我們的測(cè)試中,我們現(xiàn)在可以快速調(diào)用我們的 post factory 為我們創(chuàng)建一個(gè) post。讓我們看看我們可以如何做到這一點(diǎn):

 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');
});

一個(gè)足夠簡(jiǎn)單的測(cè)試,但是如果我們的業(yè)務(wù)規(guī)則規(guī)定你只能根據(jù)帖子類型更新特定列,會(huì)發(fā)生什么?讓我們重構(gòu)我們的測(cè)試以確保我們可以做到這一點(diǎn):

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');
});

完美,我們可以將一個(gè)參數(shù)傳遞給 create 方法,以確保我們?cè)趧?chuàng)建它時(shí)設(shè)置正確的類型,這樣我們的業(yè)務(wù)規(guī)則就不會(huì)抱怨。但是這樣寫有點(diǎn)麻煩,所以讓我們稍微重構(gòu)一下我們的工廠,添加修改狀態(tài)的方法:

 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(),
            ],
        );
    }
}

我們?yōu)楣S設(shè)置了默認(rèn)值,以便所有新創(chuàng)建的帖子都是草稿。然后我們添加一個(gè)設(shè)置要發(fā)布的狀態(tài)的方法,它將使用正確的 Enum 值并設(shè)置發(fā)布日期 - 在測(cè)試環(huán)境中更具可預(yù)測(cè)性和可重復(fù)性。讓我們看看我們的測(cè)試現(xiàn)在是什么樣子:

 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');
});

回到一個(gè)簡(jiǎn)單的測(cè)試——所以如果我們有多個(gè)測(cè)試想要?jiǎng)?chuàng)建一個(gè)草稿帖子,他們可以使用工廠。現(xiàn)在讓我們?yōu)榘l(fā)布的狀態(tài)編寫一個(gè)測(cè)試,看看是否有錯(cuò)誤。

 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);
});

這次我們正在測(cè)試當(dāng)我們嘗試更新已發(fā)布的帖子時(shí)是否收到驗(yàn)證錯(cuò)誤狀態(tài)。這可確保我們保護(hù)我們的內(nèi)容并在我們的應(yīng)用程序中強(qiáng)制執(zhí)行特定的工作流程。

那么如果我們還想確保工廠中的特定內(nèi)容會(huì)發(fā)生什么呢?我們可以根據(jù)需要添加另一種方法來修改狀態(tài):

 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),
            ],
        );
    }
}

因此,在我們的測(cè)試中,我們可以創(chuàng)建一個(gè)新測(cè)試,以確保我們可以通過我們的 API 更新草稿帖子標(biāo)題:

 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');
});

所以我們可以很好地使用工廠狀態(tài)來控制我們的測(cè)試環(huán)境中的東西,給我們盡可能多的控制權(quán)。這樣做將確保我們始終如一地準(zhǔn)備測(cè)試,或者很好地反映特定點(diǎn)的應(yīng)用程序狀態(tài)。

如果我們需要為我們的測(cè)試創(chuàng)建許多模型,我們?cè)撛趺崔k?我們應(yīng)該怎么做?簡(jiǎn)單的答案是告訴工廠:

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

    getJson(
        route('api.posts.index'),
    )->assertOk()->assertJson(fn (AssertableJson $json) =>
        $json->has(12)->etc(),
    );
});

所以我們正在創(chuàng)建 12 個(gè)新帖子,并確保當(dāng)我們獲得索引路由時(shí),我們有 12 個(gè)帖子返回。除了將 count 傳遞給工廠方法,你還可以使用 count 方法:

Post::factory()->count(12)->create();

但是,在我們的應(yīng)用程序中,有時(shí)我們可能希望以特定順序運(yùn)行事物。假設(shè)我們希望第一個(gè)是草稿,但第二個(gè)已發(fā)布?

 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();
    );
});

讀到這里,這篇“Laravel應(yīng)用程序中怎么使用模型工廠”文章已經(jīng)介紹完畢,想要掌握這篇文章的知識(shí)點(diǎn)還需要大家自己動(dòng)手實(shí)踐使用過才能領(lǐng)會(huì),如果想了解更多相關(guān)內(nèi)容的文章,歡迎關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI