
本文介绍如何在 Laravel 测试中准确验证嵌套 JSON 数组(如 items.*.id)中所有 ID 是否匹配预期值,解决原生 assertJson 不支持通配符数组比对的限制。
本文介绍如何在 laravel 测试中准确验证嵌套 json 数组(如 `items.*.id`)中所有 id 是否匹配预期值,解决原生 `assertjson` 不支持通配符数组比对的限制。
在 Laravel 的 HTTP 测试中,assertJson() 及其闭包式变体 assertJson(fn (AssertableJson $json) => ...) 功能强大,但*不支持直接使用通配符(如 `items..id)对数组元素进行批量值断言**——例如期望items中所有id恰好为[10, 20](顺序无关)。官方 API 并未提供类似whereAll('items..id', [10, 20])或whereIn('items..id', [...])的语法,因此需借助AssertableJson::toArray()` 手动提取并校验。
以下是一个健壮、可复用的解决方案:
将一个或多个视频上传至YouTube。当用户想“上传到YouTube”“发YouTube”“批量上传”“upload to YouTube”“post videos to YouTube”或发布到YouTube时使用此技能。
use Illuminate\Testing\Fluent\AssertableJson;
use Symfony\Component\HttpFoundation\Response;
public function testItemsContainExpectedIds(): void
{
$expectedIds = [10, 20];
$this->getJson('/api/items')
->assertStatus(Response::HTTP_OK)
->assertJsonIsObject()
->assertJson(function (AssertableJson $json) use ($expectedIds) {
// 断言 items 是长度为 2 的数组
$json->has('items', count($expectedIds));
// 进入 items 数组上下文,提取所有 id 值
$json->has('items', function (AssertableJson $items) use ($expectedIds) {
$actualIds = array_column($items->toArray(), 'id');
// 验证每个期望 ID 都存在于响应中(支持无序)
foreach ($expectedIds as $id) {
$this->assertContains($id, $actualIds);
}
// 【可选】进一步确保无多余 ID(即精确匹配)
$this->assertCount(count($expectedIds), $actualIds);
$this->assertEqualsCanonicalizing($expectedIds, $actualIds);
});
});
}
✅ 关键要点说明:
-
has('items', $count)确保数组长度正确,避免漏测; -
array_column($items->toArray(), 'id')将items数组扁平化为 ID 列表,兼容任意结构; - 使用
assertEqualsCanonicalizing()(Laravel 9+)或sort()+assertEquals()可实现无序精确匹配(即响应中 ID 集合必须与期望完全一致,不多不少); - 若仅需“包含”逻辑(允许额外 ID),则省略最后的
assertEqualsCanonicalizing即可; - 此方案不依赖 JSON 路径通配符,规避了底层
where()方法对数组索引的硬性绑定限制。
? 进阶提示:
可将上述逻辑封装为测试 Trait 方法,例如 assertJsonIdsInPath($path, array $expectedIds),提升多处复用性。同时注意:AssertableJson::toArray() 返回的是 PHP 数组,确保响应结构稳定(如 items 始终为数组而非 null),必要时添加 ->whereNotNull('items') 前置防护。










