0

0

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

青灯夜游

青灯夜游

发布时间:2022-11-28 20:26:22

|

1245人浏览过

|

来源于learnku

转载

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

回到一个简单的测试——所以如果我们有多个测试想要创建一个草稿帖子,他们可以使用工厂。现在让我们为发布的状态编写一个测试,看看是否有错误。

聚好用AI
聚好用AI

可免费AI绘图、AI音乐、AI视频创作,聚集全球顶级AI,一站式创意平台

下载
 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视频教程

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

WorkBuddy
WorkBuddy

腾讯云推出的AI原生桌面智能体工作台

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
laravel组件介绍
laravel组件介绍

laravel 提供了丰富的组件,包括身份验证、模板引擎、缓存、命令行工具、数据库交互、对象关系映射器、事件处理、文件操作、电子邮件发送、队列管理和数据验证。想了解更多laravel的相关内容,可以阅读本专题下面的文章。

340

2024.04.09

laravel中间件介绍
laravel中间件介绍

laravel 中间件分为五种类型:全局、路由、组、终止和自定。想了解更多laravel中间件的相关内容,可以阅读本专题下面的文章。

294

2024.04.09

laravel使用的设计模式有哪些
laravel使用的设计模式有哪些

laravel使用的设计模式有:1、单例模式;2、工厂方法模式;3、建造者模式;4、适配器模式;5、装饰器模式;6、策略模式;7、观察者模式。想了解更多laravel的相关内容,可以阅读本专题下面的文章。

774

2024.04.09

thinkphp和laravel哪个简单
thinkphp和laravel哪个简单

对于初学者来说,laravel 的入门门槛较低,更易上手,原因包括:1. 更简单的安装和配置;2. 丰富的文档和社区支持;3. 简洁易懂的语法和 api;4. 平缓的学习曲线。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

386

2024.04.10

laravel入门教程
laravel入门教程

本专题整合了laravel入门教程,想了解更多详细内容,请阅读专题下面的文章。

146

2025.08.05

laravel实战教程
laravel实战教程

本专题整合了laravel实战教程,阅读专题下面的文章了解更多详细内容。

85

2025.08.05

laravel面试题
laravel面试题

本专题整合了laravel面试题相关内容,阅读专题下面的文章了解更多详细内容。

80

2025.08.05

PHP高性能API设计与Laravel服务架构实践
PHP高性能API设计与Laravel服务架构实践

本专题围绕 PHP 在现代 Web 后端开发中的高性能实践展开,重点讲解基于 Laravel 框架构建可扩展 API 服务的核心方法。内容涵盖路由与中间件机制、服务容器与依赖注入、接口版本管理、缓存策略设计以及队列异步处理方案。同时结合高并发场景,深入分析性能瓶颈定位与优化思路,帮助开发者构建稳定、高效、易维护的 PHP 后端服务体系。

650

2026.03.04

TypeScript类型系统进阶与大型前端项目实践
TypeScript类型系统进阶与大型前端项目实践

本专题围绕 TypeScript 在大型前端项目中的应用展开,深入讲解类型系统设计与工程化开发方法。内容包括泛型与高级类型、类型推断机制、声明文件编写、模块化结构设计以及代码规范管理。通过真实项目案例分析,帮助开发者构建类型安全、结构清晰、易维护的前端工程体系,提高团队协作效率与代码质量。

49

2026.03.13

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
PHP课程
PHP课程

共137课时 | 13.5万人学习

JavaScript ES5基础线上课程教学
JavaScript ES5基础线上课程教学

共6课时 | 11.3万人学习

PHP新手语法线上课程教学
PHP新手语法线上课程教学

共13课时 | 1.0万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号