Featured image of post Laravel 測試只驗 View Data,不碰 HTML

Laravel 測試只驗 View Data,不碰 HTML

複雜頁面測 HTML 很脆弱,改用 viewData() 直接驗 View 變數更穩定;比較 Model 時用 id 或 toArray() 而非直接 assertEquals 物件。

Laravel Feature Test 遇到複雜的畫面時,直接測 HTML 很痛苦,其實可以只測傳給 View 的資料。

用 viewData 取回 View 變數

$response->viewData('key') 可以直接取回傳給 View 的變數:

1
2
3
4
5
6
// routes/web.php
Route::get('/', function () {
    return view('welcome', [
        'foo' => 'bar',
    ]);
});
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
namespace Tests\Feature;

use Tests\TestCase;

class ExampleTest extends TestCase
{
    public function test_only_view_data(): void
    {
        $response = $this->get('/')->assertOk();

        self::assertEquals('bar', $response->viewData('foo'));
    }
}

比較 Model 時要注意物件同一性

當 View data 包含從資料庫撈出來的 Model 時,直接用 assertEquals 比較兩個 Model 物件會失敗:

1
2
3
4
5
6
7
8
9
// routes/web.php
Route::get('/', function () {
    $user = User::firstOrFail();

    return view('welcome', [
        'foo' => 'bar',
        'user' => $user,
    ]);
});
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
class ExampleTest extends TestCase
{
    use RefreshDatabase;

    public function test_only_view_data(): void
    {
        /** @var User $user */
        $user = User::factory()->create();

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

        self::assertEquals('bar', $response->viewData('foo'));
        // 這行會失敗,因為 route 裡重新從 DB 撈了一次,不是同一個物件
        self::assertEquals($user, $response->viewData('user'));
    }
}

原因是 route 裡面會重新從資料庫取出 User,雖然資料相同但不是同一個物件實例。改成比較 attributes 就好:

1
2
self::assertEquals($user->id, $response->viewData('user')->id);
self::assertEquals($user->toArray(), $response->viewData('user')->toArray());

viewData 只能驗資料有沒有正確傳到 View,前端的 JavaScript、CSS 以及 Blade template 有沒有正確輸出變數,這個方法是測不到的。