HTTP 測試

介紹

Laravel 提供了一個非常優雅的 API 來向你的應用程式發出 HTTP 請求並檢查輸出。如下面定義的測試:

<?php

namespace Tests\Feature;

use Tests\TestCase;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithoutMiddleware;

class ExampleTest extends TestCase
{
    /**
     * 一個基本測試範例。
     *
     * @return void
     */
    public function testBasicTest()
    {
        $response = $this->get('/');

        $response->assertStatus(200);
    }
}

get 方法會建立一個 GET 請求給應用程式,而 assertStatus 方法來斷言所回傳的回應會有給定的 HTTP 狀態碼。除了這個簡易的斷言,Laravel 也包含用來檢查回應的 Header、內容、JSON 結構等的各種斷言。

自訂請求 Header

你可以在發送 Header 之前使用 withHeaders 方法來自訂請求的 Header。這可以讓你來新增想要的任何自訂請求 Header:

<?php

class ExampleTest extends TestCase
{
    /**
     * 一個基本功能測試範例。
     *
     * @return void
     */
    public function testBasicExample()
    {
        $response = $this->withHeaders([
            'X-Header' => 'Value',
        ])->json('POST', '/user', ['name' => 'Sally']);

        $response
            ->assertStatus(200)
            ->assertJson([
                'created' => true,
            ]);
    }
}

Session 和認證

Laravel 提供幾個在 HTTP 測試期間會搭配 Session 一起測試的輔助函式。首先,你可以使用 withSession 方法來設定 Session 資料來取得陣列。這樣有助於在發送請求到你的應用程式前載入 Session 與資料:

<?php

class ExampleTest extends TestCase
{
    public function testApplication()
    {
        $response = $this->withSession(['foo' => 'bar'])
                         ->get('/');
    }
}

當然,Session 常被用於維持已認證使用者的狀態。actingAs 輔助函式方法提供一個簡易的方式來認證當前的使用者。例如,我們使用模型工廠 來產生並認證使用者:

<?php

use App\User;

class ExampleTest extends TestCase
{
    public function testApplication()
    {
        $user = factory(User::class)->create();

        $response = $this->actingAs($user)
                         ->withSession(['foo' => 'bar'])
                         ->get('/');
    }
}

你也可以透過將 guard 名稱作為第二個參數傳送給 actingAs 方法來指定應該使用那個守衛來驗證給定的使用者:

$this->actingAs($user, 'api')

測試 JSON API

Laravel 還提供數個測試 JSON API 與回應的輔助函式。例如,jsongetpostputpatchdelete 方法可被用於發出各種 HTTP 動詞的請求。你還可以輕易的將資料和標頭傳入這些方法。讓我們開始撰寫一個測試來建立 POST 請求到 /user 並斷言已回傳的預期資料:

<?php

class ExampleTest extends TestCase
{
    /**
     * 一個基本功能測試範例。
     *
     * @return void
     */
    public function testBasicExample()
    {
        $response = $this->json('POST', '/user', ['name' => 'Sally']);

        $response
            ->assertStatus(200)
            ->assertJson([
                'created' => true,
            ]);
    }
}

{tip}assertJson 方法會把回應轉換成陣列,並採用 PHPUnit::assertArraySubset 來驗證剛回傳的 JSON 回應中是否存在給定的陣列。所以,如果 JSON 回應中有其他的屬性,只有給定的陣列值存在,這個測試仍然會通過。

驗證是否與 JSON 完全匹配

如果你希望驗證給定的陣列是否與應用程式回傳的 JSON 完全匹配,你應該使用 assertExactJson 方法:

<?php

class ExampleTest extends TestCase
{
    /**
     * 一個基本功能測試範例。
     *
     * @return void
     */
    public function testBasicExample()
    {
        $response = $this->json('POST', '/user', ['name' => 'Sally']);

        $response
            ->assertStatus(200)
            ->assertExactJson([
                'created' => true,
            ]);
    }
}

測試檔案上傳

Illuminate\Http\UploadedFile 類別提供 fake 方法可以用來產生虛擬檔案或圖像來進行測試。若與 Storage facade 的 fake 方法的搭配組合可以大大簡化檔案上傳的測試。例如,你可以組合這兩個功能來輕易的測試頭像上傳表單:

<?php

namespace Tests\Feature;

use Tests\TestCase;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Storage;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithoutMiddleware;

class ExampleTest extends TestCase
{
    public function testAvatarUpload()
    {
        Storage::fake('avatars');

        $response = $this->json('POST', '/avatar', [
            'avatar' => UploadedFile::fake()->image('avatar.jpg')
        ]);

        // 斷言檔案使否有儲存...
        Storage::disk('avatars')->assertExists('avatar.jpg');

        // 斷言檔案是否不存在...
        Storage::disk('avatars')->assertMissing('missing.jpg');
    }
}

自訂假檔案

使用 fake 方法來建立檔案時,你可以為了更好的測試驗證規則而指定圖像的寬、高和其他尺寸:

UploadedFile::fake()->image('avatar.jpg', $width, $height)->size(100);

除了建立圖片,你可以使用 create 方法來建立任何類型的檔案:

UploadedFile::fake()->create('document.pdf', $sizeInKilobytes);

可用的斷言

Laravel 為你的 PHPUnit 測試提供了各種自訂的斷言方法。這些斷言可以存取從 jsongetpostputdelete 測試方法所回傳的回應:

方法 說明
$response->assertSuccessful(); 斷言回應是否有成功的狀態碼。
$response->assertStatus($code); 斷言回應是否有給定的狀態碼。
$response->assertRedirect($uri); 斷言回應是否導回給定的 URI。
$response->assertHeader($headerName, $value = null); 斷言給定的標頭是否存在於回應上。
$response->assertCookie($cookieName, $value = null); 斷言回應是否包含給定的 cookie。
$response->assertPlainCookie($cookieName, $value = null); 斷言回應是否包含給定的 cookie (已加密)。
$response->assertCookieExpired($cookieName); 斷言回應是否包含給定的 cookie 與有效期限。
$response->assertCookieMissing($cookieName); 斷言回應有沒有不包含給定的 cookie
$response->assertSessionHas($key, $value = null); 斷言 session 是否包含給的資料片段。
$response->assertSessionHasErrors(array $keys, $format = null, $errorBag = 'default'); 斷言 session 是否包含給定字段的錯誤。
$response->assertSessionMissing($key); 斷言 session 是否不包含給定的金鑰。
$response->assertJson(array $data); 斷言回應是否包含給定的 JSON 資料。
$response->assertJsonFragment(array $data); 斷言回應是否包含給定的 JSON 片段。
$response->assertJsonMissing(array $data); 斷言回應是否不包含給定的 JSON 片段。
$response->assertExactJson(array $data); 斷言回應是否與包含給定的 JSON 資料完全匹配。
$response->assertJsonStructure(array $structure); 斷言回應是否有給定的 JSON 結構。
$response->assertViewIs($value); 斷言給定視圖是否從路由回傳。
$response->assertViewHas($key, $value = null); 斷言回應的視圖是否有給定的資料片段。
$response->assertViewHasAll(array $data); 斷言回應的視圖是否有給定的資料列表。
$response->assertViewMissing($key); 斷言回應的視圖是否缺少範圍內的資料。
$response->assertSee($value); 斷言給定的字串是否包含在回應中。
$response->assertDontSee($value); 斷言給定的字串是否不包含在回應中。
$response->assertSeeText($value); 斷言給定的字串是否包含在回應文本中。
$response->assertDontSeeText($value); 斷言給定字串是否不包含在回應文本中。