如何在Laravel应用程序中使用模型工厂?

发布时间 - 2022-11-28 00:00:00    点击率:

如何在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视频教程】


# php  # laravel  # count  # 子类  # enum  # 字符串  # 数据库  # https  # 重构  # 让我们  # 我们可以  # 应用程序  # 创建一个  # 在这里  # 很好  # 在我们的  # 有一个  # 可以使用  # 我们现在 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: Python正则表达式进阶教程_复杂匹配与分组替换解析  EditPlus中的正则表达式实战(5)  西安市网站制作公司,哪个相亲网站比较好?西安比较好的相亲网站?  Laravel怎么定时执行任务_Laravel任务调度器Schedule配置与Cron设置【教程】  香港代理服务器配置指南:高匿IP选择、跨境加速与SEO优化技巧  php485函数参数是什么意思_php485各参数详细说明【介绍】  如何快速搭建个人网站并优化SEO?  微信公众帐号开发教程之图文消息全攻略  laravel怎么配置和使用PHP-FPM来优化性能_laravel PHP-FPM配置与性能优化方法  如何用花生壳三步快速搭建专属网站?  北京网站制作费用多少,建立一个公司网站的费用.有哪些部分,分别要多少钱?  Laravel如何实现多级无限分类_Laravel递归模型关联与树状数据输出【方法】  iOS中将个别页面强制横屏其他页面竖屏  消息称 OpenAI 正研发的神秘硬件设备或为智能笔,富士康代工  Laravel控制器是什么_Laravel MVC架构中Controller的作用与实践  如何为不同团队 ID 动态生成多个“认领值班”按钮  合肥制作网站的公司有哪些,合肥聚美网络科技有限公司介绍?  如何快速使用云服务器搭建个人网站?  Python高阶函数应用_函数作为参数说明【指导】  Laravel与Inertia.js怎么结合_使用Laravel和Inertia构建现代单页应用  如何快速生成ASP一键建站模板并优化安全性?  javascript中数组(Array)对象和字符串(String)对象的常用方法总结  如何在建站之星绑定自定义域名?  如何自己制作一个网站链接,如何制作一个企业网站,建设网站的基本步骤有哪些?  Laravel怎么实现模型属性转换Casting_Laravel自动将JSON字段转为数组【技巧】  百度浏览器ai对话怎么关 百度浏览器ai聊天窗口隐藏  Laravel广播系统如何实现实时通信_Laravel Reverb与WebSockets实战教程  Laravel Eloquent访问器与修改器是什么_Laravel Accessors & Mutators数据处理技巧  Laravel怎么写单元测试_PHPUnit在Laravel项目中的基础测试入门  Laravel的辅助函数有哪些_Laravel常用Helpers函数提高开发效率  Internet Explorer官网直接进入 IE浏览器在线体验版网址  高配服务器限时抢购:企业级配置与回收服务一站式优惠方案  如何用免费手机建站系统零基础打造专业网站?  JavaScript如何实现错误处理_try...catch如何捕获异常?  Midjourney怎么调整光影效果_Midjourney光影调整方法【指南】  Android中Textview和图片同行显示(文字超出用省略号,图片自动靠右边)  浅析上传头像示例及其注意事项  Win11摄像头无法使用怎么办_Win11相机隐私权限开启教程【详解】  如何生成腾讯云建站专用兑换码?  Laravel怎么使用Markdown渲染文档_Laravel将Markdown内容转HTML页面展示【实战】  PHP怎么接收前端传的文件路径_处理文件路径参数接收方法【汇总】  Claude怎样写约束型提示词_Claude约束提示词写法【教程】  为什么php本地部署后css不生效_静态资源加载失败修复技巧【技巧】  非常酷的网站设计制作软件,酷培ai教育官方网站?  Laravel如何清理系统缓存命令_Laravel清除路由配置及视图缓存的方法【总结】  Windows10电脑怎么设置虚拟光驱_Win10右键装载ISO镜像文件  如何快速查询域名建站关键信息?  Android仿QQ列表左滑删除操作  济南网站建设制作公司,室内设计网站一般都有哪些功能?  如何快速生成凡客建站的专业级图册?