如何在Laravel應(yīng)用程序中使用模型工廠?

如何在laravel應(yīng)用程序中使用模型工廠?下面本篇文章給大家介紹一下在測(cè)試中使用 laravel 模型工程的方法,希望對(duì)大家有所幫助!

如何在Laravel應(yīng)用程序中使用模型工廠?

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

讓我們從一個(gè)簡(jiǎn)單的例子開(kāi)始。我們有一個(gè)用于寫(xiě)博客的應(yīng)用程序,所以很自然地,我們有一個(gè) Post 模型,該模型具有發(fā)布、起草或排隊(duì)的狀態(tài)。讓我們看一下這個(gè)例子的 Eloquent 模型:

declare(strict_types=1);  namespace?AppModels;  use?AppPublishingenumsPostStatus; use?IlluminateDatabaseModel;  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ù)庫(kù)枚舉。

?declare(strict_types=1);  namespace?AppPublishingEnums;  enum?PostStatus:?string { ????case?PUBLISHED?=?'published'; ????case?DRAFT?=?'draft'; ????case?QUEUED?=?'queued'; }

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

?declare(strict_types=1);  namespace?DatabaseFactories;  use?AppModelsPost; use?AppPublishingEnumsPostStatus; use?IlluminateDatabaseEloquentFactoriesFactory; use?IlluminateSupportArr; use?IlluminateSupportStr;  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ì)抱怨。但是這樣寫(xiě)有點(diǎn)麻煩,所以讓我們稍微重構(gòu)一下我們的工廠,添加修改狀態(tài)的方法:

?declare(strict_types=1);  namespace?DatabaseFactories;  use?AppModelsPost; use?AppPublishingEnumsPostStatus; use?IlluminateDatabaseEloquentFactoriesFactory; use?IlluminateSupportStr;  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)編寫(xiě)一個(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ù)需要添加另一種方法來(lái)修改狀態(tài):

?declare(strict_types=1);  namespace?DatabaseFactories;  use?AppModelsPost; use?AppPublishingEnumsPostStatus; use?IlluminateDatabaseEloquentFactoriesFactory; use?IlluminateSupportStr;  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è)試,以確保我們可以通過(guò)我們的 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)來(lá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(); ????); });

你如何在應(yīng)用程序中使用模型工廠?你有沒(méi)有找到任何很酷的方法來(lái)使用它們?在 twitter 上告訴我們!

原文地址:https://laravel-news.com/laravel-model-factories譯文地址:https://learnku.com/laravel/t/70290

【相關(guān)推薦:laravel視頻教程

? 版權(quán)聲明
THE END
喜歡就支持一下吧
點(diǎn)贊9 分享