Laravel 测试中工厂模型时间戳手动赋值导致数据库查询失败的解决方案

小萱吖_7788

小萱吖_7788

2026-09-06

226人浏览

原创

Laravel 测试中工厂模型时间戳手动赋值导致数据库查询失败的解决方案

Laravel 功能测试中,若在模型工厂中手动设置 created_at、updated_at 或 deleted_at 等时间戳字段,会导致内存数据库(SQLite in-memory)中记录虽存在但 Eloquent 查询失败,典型表现为“Model not found”异常,而原始 SQL 查询却能查到数据。

laravel 功能测试中,若在模型工厂中手动设置 `created_at`、`updated_at` 或 `deleted_at` 等时间戳字段,会导致内存数据库(sqlite in-memory)中记录虽存在但 eloquent 查询失败,典型表现为“model not found”异常,而原始 sql 查询却能查到数据。

在 Laravel 的功能测试中,尤其是使用 RefreshDatabase 特性配合内存数据库(如 sqlite::memory:)时,Eloquent 的时间戳自动管理机制与手动干预之间存在关键冲突——这正是你遇到 "No query results for model" 错误的根本原因。

? 问题根源分析

你的 TeamFactory 中显式设置了时间戳:

'deleted_at' => Carbon::now(),
'created_at' => Carbon::now(),
'updated_at' => Carbon::now(),

这看似无害,实则破坏了 Laravel 的时间戳生命周期契约:

  • Eloquent 默认在 save() 时由模型自身自动填充 created_at/updated_at(受 $timestamps = true 和 protected $dates 控制);
  • 若工厂中提前写入固定时间值(尤其是 Carbon::now()),该时间可能早于事务开启时刻,或与内存数据库的时钟上下文不一致;
  • 更严重的是:当模型启用软删除(SoftDeletes)且 deleted_at 被设为非-null 值(如 Carbon::now())时,Eloquent 默认会隐藏所有 deleted_at IS NOT NULL 的记录——即使你尚未调用 delete(),该记录在常规查询中已被逻辑过滤掉,Team::find($id) 失败,而底层 DB::table('teams')->where('id', ...)->first() 却能查到(因绕过 Eloquent 作用域)。

✅ 验证方式:

// 在测试中添加调试
dump(Team::withTrashed()->find($this->team->id)); // 可能返回结果
dump(Team::find($this->team->id)); // 返回 null(因 deleted_at 非空)

✅ 正确的工厂写法(推荐)

移除所有手动时间戳赋值,交还控制权给 Eloquent:

// database/factories/TeamFactory.php
class TeamFactory extends Factory
{
    protected $model = Team::class;

    public function definition(): array
    {
        return [
            'id' => Str::uuid(),
            'name' => $this->faker->company(), // 使用更语义化的 faker 方法
            // ❌ 删除以下三行:
            // 'deleted_at' => Carbon::now(),
            // 'created_at' => Carbon::now(),
            // 'updated_at' => Carbon::now(),
        ];
    }
}

? 提示:Laravel 会自动处理 created_at/updated_at;若需软删除测试,应使用 softDeleted() 状态方法,而非硬编码 deleted_at。

laravel-specialist
laravel-specialist

精通 Laravel 10+,遵循现代 PHP 实践的 Laravel 专家。擅长优雅语法、Eloquent ORM、队列系统及企业级特性...

下载

? 补充建议:确保测试环境一致性

  1. 确认模型启用了时间戳(默认开启,但需检查):

    // App\Models\Team.php
    public $timestamps = true; // 必须为 true
    use SoftDeletes; // 若启用软删除,确保此 trait 存在
  2. 避免在工厂中生成重复 UUID 冲突(可选增强):

    'id' => fn () => (string) Str::uuid(),
  3. 在测试中显式验证记录状态:

    public function testUserCanDeleteItsOwnTeam()
    {
        $this->createTeam();
    
        // 确保记录处于活跃状态(未被软删除)
        $this->assertNotNull($this->team->refresh()->created_at);
        $this->assertNull($this->team->deleted_at);
    
        $this->useToken()
             ->deleteJson(route('team.delete', ['team' => $this->team->id]))
             ->assertOk();
    }

? 总结

  • ⚠️ 永远不要在工厂中手动设置 created_at/updated_at/deleted_at —— 这违背 Laravel 的自动化约定,尤其在内存数据库中引发不可预测的行为;
  • ✅ 工厂职责是定义业务属性(如 name, slug, 关联关系等),时间戳和软删除状态应由 Eloquent 模型层统一管控;
  • ? 遇到 “记录存在但查不到” 类问题,优先检查:软删除状态、时间戳干扰、数据库连接隔离性(是否真在同一个事务/内存实例中)。

修复后,你的 testUserCanDeleteItsOwnTeam 将稳定通过,且符合 Laravel 最佳实践。

相关文章

PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

laravel

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
php文件怎么打开
php文件怎么打开

打开php文件步骤:1、选择文本编辑器;2、在选择的文本编辑器中,创建一个新的文件,并将其保存为.php文件;3、在创建的PHP文件中,编写PHP代码;4、要在本地计算机上运行PHP文件,需要设置一个服务器环境;5、安装服务器环境后,需要将PHP文件放入服务器目录中;6、一旦将PHP文件放入服务器目录中,就可以通过浏览器来运行它。

2023.09.01

11224

6

php怎么取出数组的前几个元素
php怎么取出数组的前几个元素

取出php数组的前几个元素的方法有使用array_slice()函数、使用array_splice()函数、使用循环遍历、使用array_slice()函数和array_values()函数等。本专题为大家提供php数组相关的文章、下载、课程内容,供大家免费下载体验。

2023.10.11

6521

5

php反序列化失败怎么办
php反序列化失败怎么办

php反序列化失败的解决办法检查序列化数据。检查类定义、检查错误日志、更新PHP版本和应用安全措施等。本专题为大家提供php反序列化相关的文章、下载、课程内容,供大家免费下载体验。

2023.10.11

2155

5

php怎么连接mssql数据库
php怎么连接mssql数据库

连接方法:1、通过mssql_系列函数;2、通过sqlsrv_系列函数;3、通过odbc方式连接;4、通过PDO方式;5、通过COM方式连接。想了解php怎么连接mssql数据库的详细内容,可以访问下面的文章。

2023.10.23

4128

4

php连接mssql数据库的方法
php连接mssql数据库的方法

php连接mssql数据库的方法有使用PHP的MSSQL扩展、使用PDO等。想了解更多php连接mssql数据库相关内容,可以阅读本专题下面的文章。

2023.10.23

4834

6

html怎么上传
html怎么上传

html通过使用HTML表单、JavaScript和PHP上传。更多关于html的问题详细请看本专题下面的文章。php中文网欢迎大家前来学习。

2023.11.03

3791

9

PHP出现乱码怎么解决
PHP出现乱码怎么解决

PHP出现乱码可以通过修改PHP文件头部的字符编码设置、检查PHP文件的编码格式、检查数据库连接设置和检查HTML页面的字符编码设置来解决。更多关于php乱码的问题详情请看本专题下面的文章。php中文网欢迎大家前来学习。

2023.11.09

5457

8

php文件怎么在手机上打开
php文件怎么在手机上打开

php文件在手机上打开需要在手机上搭建一个能够运行php的服务器环境,并将php文件上传到服务器上。再在手机上的浏览器中输入服务器的IP地址或域名,加上php文件的路径,即可打开php文件并查看其内容。更多关于php相关问题,详情请看本专题下面的文章。php中文网欢迎大家前来学习。

2023.11.13

4262

8

sprintf函数用法详解
sprintf函数用法详解

sprintf函数的用法:1、格式化字符串;2、指定输出宽度和精度;3、返回值。更多关于sprintf函数用法详解的内容,大家可以阅读下面的文章。

2023.11.27

12202

4

热门下载

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

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
如何安装 Composer
如何安装 Composer

共1课时 | 210人学习

Composer手册
Composer手册

共0课时 | 0人学习