Laravel中如何在工厂生成合法JSON以通过PHPUnit验证?
解决Laravel工厂生成JSON数据无法通过验证的问题
问题根源
核心矛盾在于模型字段转换和验证规则的不匹配:
- 模型中
$casts = ['settings' => 'array']会自动将赋值的JSON字符串转为数组,或把数组转为JSON字符串存储到数据库。 - 测试中用
make()创建模型实例后调用toArray(),settings会以数组形式输出,但控制器验证规则要求的是JSON格式的字符串,导致验证失败。 - 另外,工厂中
name字段使用$this->faker->words(3,7)返回的是数组,不符合name字段string的验证规则,这也是潜在问题。
解决方案
方案1:使用工厂raw()方法获取原始数据
raw()方法直接返回工厂定义的原始数组,不会经过模型的字段转换处理,确保settings是JSON字符串格式:
- 修正工厂代码(同时修复
name字段的问题):
class ExampleFactory extends Factory { protected $model = Example::class; public function definition() { return [ 'name' => $this->faker->sentence(3), // 返回字符串,符合验证规则 'settings' => json_encode(['areas' => ['full', 'city']]) ]; } }
- 修改测试代码,使用
raw()获取数据:
/** @test */ public function shouldStore(): void { $data = $this->model::factory()->raw(); $this->post(action([$this->controller, 'store']), $data) ->assertOk(); }
方案2:测试中手动转换settings为JSON字符串
如果仍想使用make()方法,可在转换数组后手动将settings重新编码为JSON字符串:
- 工厂中直接使用数组定义
settings(更直观):
public function definition() { return [ 'name' => $this->faker->sentence(3), 'settings' => ['areas' => ['full', 'city']] ]; }
- 测试中处理数据:
/** @test */ public function shouldStore(): void { $item = $this->model::factory()->make(); $data = $item->toArray(); $data['settings'] = json_encode($data['settings']); // 将数组转回JSON字符串 $this->post(action([$this->controller, 'store']), $data) ->assertOk(); }
方案3:调整验证规则为array(业务允许时)
如果业务支持前端提交数组格式的settings,可以修改模型的验证规则,让数组和JSON字符串都能通过验证(Laravel会自动解析JSON字符串为数组):
public static $rules = [ 'name' => 'required|string|max:255', 'settings' => 'nullable|array' ];
此时工厂中直接用数组定义settings,测试中toArray()后的数组能直接通过验证,模型的cast会自动将其转为JSON字符串存储。
内容的提问来源于stack exchange,提问作者Ferenc Bablena
相关产品推荐
相关产品推荐

