
在 Laravel 测试中,无法直接用 items.*.id 匹配无序 ID 数组,需结合 toArray() 提取 ID 列表并手动校验是否完全包含预期值。
在 laravel 测试中,无法直接用 `items.*.id` 匹配无序 id 数组,需结合 `toarray()` 提取 id 列表并手动校验是否完全包含预期值。
Laravel 的 assertJson() 链式断言(基于 AssertableJson)功能强大,但其通配符语法(如 items.*.id)不支持将多个匹配结果聚合为数组后进行整体比对——它仅适用于逐项断言或结构验证,而非集合内容等价性校验。例如,$json->where('items.*.id', [10, 20]) 实际上会尝试对每个 items.* 子项分别执行 where('id', [10, 20]),这在语义和实现上均不可行。
✅ 正确解法是:利用 AssertableJson::toArray() 获取解析后的 PHP 数组,再通过 array_column() 提取所有 id 值,最后使用 PHPUnit 的 assertContains() 或更严格的 assertEqualsCanonicalizing() 进行内容校验。
以下是一个健壮、可复用的测试示例:
将一个或多个视频上传至YouTube。当用户想“上传到YouTube”“发YouTube”“批量上传”“upload to YouTube”“post videos to YouTube”或发布到YouTube时使用此技能。
public function testItemsContainExpectedIds(): void
{
$expectedIds = [10, 20];
$this->getJson('/api/items')
->assertStatus(200)
->assertJsonIsObject()
->assertJson(fn (AssertableJson $json) => $json
->has('items', count($expectedIds)) // 先确保 items 数量匹配
->has('items', function (AssertableJson $items) use ($expectedIds) {
$actualIds = array_column($items->toArray(), 'id');
// ✅ 推荐:校验两个数组元素完全相同(忽略顺序)
$this->assertEqualsCanonicalizing($expectedIds, $actualIds);
// ⚠️ 替代方案(仅校验存在性,不保证无多余项):
// foreach ($expectedIds as $id) {
// $this->assertContains($id, $actualIds);
// }
})
);
}? 关键注意事项:
- 使用
assertEqualsCanonicalizing()可严格验证expectedIds与实际提取的id列表元素完全一致且数量相等(自动忽略顺序),比循环assertContains()更安全; - 务必前置调用
->has('items', count($expectedIds)),防止因数据缺失导致array_column()返回空数组而误判; - 避免依赖
where()配合通配符做集合断言——这是常见误区,Laravel 官方文档亦未支持该用法; - 若需深度校验每个 item 的完整结构(如
id+field组合),可改用has('items.*', fn ($item) => $item->where(...)->etc())逐项断言。
此方法兼顾可读性、健壮性与 Laravel 最佳实践,适用于任何需要验证 JSON 数组中字段集合(如 ID、slug、status)的场景。

















