You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel中使用Paginator对象测试时的断言失败问题

Laravel控制器测试中assertViewHas验证分页器对象失败的解决方案

问题场景

控制器代码:

public function index()
{
    $title = "Our list of genres"; 
    $genres = Genre::paginate(20);
    return view('lists-view.genres-list', compact('genres', 'title'));
}

对应的测试代码:

// 填充数据库
(new Genre())::factory(20)->create();
// 获取20条分类数据
$genres = Genre::paginate(20);

$response = $this->get('/genres');

$response->assertStatus(200);
$response->assertSee("Our list of genres");
$response->assertViewHas('title', "Our list of genres");
$response->assertViewHas('genres',$genres);

执行测试时,$response->assertViewHas('genres',$genres);断言失败,错误信息显示两个分页器对象的path和options中的path不一致:

Failed asserting that two objects are equal.
--- Expected
+++ Actual
@@ @@
     'items' => Illuminate\Database\Eloquent\Collection Object (...)
     'perPage' => 20
     'currentPage' => 1
-    'path' => 'http://books-store.loc'
+    'path' => 'http://books-store.loc/genres'
     'query' => Array ()
     'fragment' => null
     'pageName' => 'page'
     'onEachSide' => 3
     'options' => Array (
-        'path' => 'http://books-store.loc'
+        'path' => 'http://books-store.loc/genres'
         'pageName' => 'page'
     )
     'total' => 20
     'lastPage' => 1
 )

原因分析

控制器中调用paginate()时,Laravel会自动根据当前HTTP请求的URL(即/genres)设置分页器的path属性;而测试中手动创建的$genres分页器对象,是基于CLI环境的默认域名(无请求路径)生成的,两者的path属性自然不一致,导致对象全等断言失败。

解决方案

方案一:验证分页器核心数据(推荐)

测试的核心是确认传递给视图的分页数据正确,而非分页器对象的所有属性(比如URL路径这类和请求上下文绑定的属性)。可以使用闭包形式的assertViewHas,只验证关键数据:

$response->assertViewHas('genres', function ($paginator) {
    // 验证总条数、每页条数、当前页、数据数量
    return $paginator->total() === 20
        && $paginator->perPage() === 20
        && $paginator->currentPage() === 1
        && $paginator->items()->count() === 20;
});

如果需要更细致验证数据内容,可以对比数据的标识字段(比如id):

$response->assertViewHas('genres', function ($paginator) {
    $expectedIds = Genre::all()->pluck('id');
    return $paginator->items()->pluck('id')->equals($expectedIds)
        && $paginator->total() === 20;
});

方案二:同步测试中分页器的请求路径

如果一定要断言整个分页器对象,可以手动设置测试中分页器的请求路径,使其和控制器中的一致:

// 填充数据库
(new Genre())::factory(20)->create();

// 先模拟请求上下文,让paginate()自动获取正确的path
$this->get('/genres');
$genres = Genre::paginate(20);

// 再次发起请求并断言
$response = $this->get('/genres');
// ...其他断言
$response->assertViewHas('genres', $genres);

或者直接设置请求上下文的路径:

// 填充数据库
(new Genre())::factory(20)->create();

// 设置当前请求的路径
app('request')->setPathInfo('/genres');
$genres = Genre::paginate(20);

$response = $this->get('/genres');
// ...其他断言
$response->assertViewHas('genres', $genres);

总结

无需强行修改分页器的options属性,因为URL路径属于请求上下文相关的细节,并非业务测试的核心。使用闭包验证分页器的核心数据,既能确保视图获取到正确的分页数据,也能让测试更健壮、聚焦业务逻辑。

内容的提问来源于stack exchange,提问作者AlexZelenskiy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 21:07:25