Laravel NotificationFake sendNow UUID主键触发非法偏移类型错误
问题原因
测试抛出TypeError : Illegal offset type错误的核心原因是:测试环境下创建的Responder模型实例主键值是Uuid对象而非字符串,Notification::fake()内部记录发送通知时,会用$notifiable->getKey()作为数组索引,对象类型不能作为数组键,因此触发报错。
具体逻辑冲突点:
- 你在模型
boot方法的creating回调中调用Str::uuid()生成主键,这个方法返回的是Ramsey UUID对象实例,不是字符串类型。 - 业务代码中调用
notify()的Responder实例是通过get()从数据库查询得到的:UUID对象写入数据库时会被自动转为字符串存储,查询出的属性也是字符串类型,因此不会报错。 - 测试中通过Factory调用
create()创建模型后,没有经过数据库重新读取的步骤,模型实例上的主键仍保留为对象类型,触发了NotificationFake的类型错误。 - Factory中定义的
uuid字段和模型自动生成UUID的逻辑存在冗余冲突,会干扰主键赋值逻辑。
修复方法
按以下两步修改即可解决问题:
- 修正模型UUID生成逻辑,生成后转为字符串再赋值,从根源避免主键出现对象类型:
// 修改Responder模型boot方法中的creating回调 static::creating(function($model) { // 调用toString()把Uuid对象转为字符串 $model->setAttribute($model->getKeyName(), Str::uuid()->toString()); }); - 移除ResponderFactory中冗余的uuid字段定义,避免和模型自动生成主键的逻辑冲突:
public function definition() { return [ // 删除'uuid' => $this->faker->uuid, 这一行 'diagnostic_event_id' => DiagnosticEvent::factory()->lazy(), 'school_id' => School::factory()->lazy(), 'user_id' => User::factory()->lazy(), 'occupation_id' => $this->faker->numberBetween(1,13), 'years' => $this->faker->numberBetween(1,5), 'status' => 'created', 'created_at' => now(), 'updated_at' => now() ]; }
临时替代方案:如果暂时不想修改模型逻辑,也可以在测试中创建Responder后调用refresh()方法,从数据库重新读取模型属性,让主键转为字符串:
$responder = Responder::factory()->create()->refresh();
这种方式只能解决当前测试的问题,无法覆盖其他可能用到主键的场景,不推荐优先使用。
内容的提问来源于stack exchange,提问作者Lars Fransén
相关产品推荐
相关产品推荐

