Laravel – Unit Test 單元測試教學

Laravel 整合了 phpunit 製作單元/功能測試,我們以空專案 blog 來進行範例。

cd blog
composer create-project --prefer-dist laravel/laravel .

資料庫設定

寫測試的時候,建立一份專門提供給測試的資料庫,避免與實際運作的開發環境共用。根目錄底下,複製一份 .env 為 .env.testing 並修改內容,運行測試的時候透過 artisan 指令添加參數 –env=testing 將會覆蓋 .env 的值

// .env.testing
....
DB_DATABASE=測試資料庫名稱
DB_USERNAME=測試使用者帳號
DB_PASSWORD=測試使用者密碼

修正 DB 支援的問題

若出現 Syntax error or access violation: 1071 Specified key was too long; max key length is 767 bytes 那麼請修改 app/Providers/AppServiceProvider.php

use Illuminate\Support\Facades\Schema;
 
public function boot()
{
    Schema::defaultStringLength(191);
}

建立 Migration

一開始先建立 DB Schema

php artisan make:migration create_posts_table
// database\migrations\2019_08_19_071005_create_posts_table.php
public function up()
{
    Schema::create('posts', function (Blueprint $table) {
        $table->bigIncrements('id');
        $table->string('title', 50);
        $table->longText('content');
        $table->timestamps();
    });
}

記住,我們要運行在測試資料庫

php artisan config:clear // 記得清除快取,使之可以讀取 testing
php artisan migrate --env=testing

建立資料表 Posts

php artisan make:model Post

建立測試資料工廠

這裡的工廠 PostFactory 負責定義我們的假資料工廠,只要返回我們需要的欄位即可

php artisan make:factory PostFactory --model=Post
// database\factories\PostFactory.php
$factory->define(Post::class, function (Faker $faker) {
    return [
        'title' => $faker->word,
        'content' => $faker->paragraph
    ];
});

建立單元測試

我們在單元測試中會做這幾件事情

  • 建立兩筆資料
  • 驗證是否符合預期
  • 刪除測試資料
php artisan make:test PostTest --unit

可以建立多個方法來進行測試,命名的規則例如

  • testExample() 在測試顯示時的名稱叫做 Example
  • testUserRegister() 在測試顯示時的名稱叫做 User register

我們嘗試編寫

// tests\Unit\PostTest.php

use App\Post;

class PostTest extends TestCase
{
    // 可以重整資料表,避免測試資料不斷累積。注意這會刪除所有資料,不要用在正式環境
    use RefreshDatabase;

    public function testExample()
    {
        // 建立5筆資料
        factory(Post::class, 5)->create();

        // 取得所有資料
        $posts = Post::all();

        // 斷言結果
        $this->assertCount(5, $posts);
    }
}

接著運行測試,但很重要的記得清除緩存 config:clear,讓測試環境能抓取 .env.testing。

php artisan config:clear

(Windows)
vendor\bin\phpunit

(Linux)
vendor/bin/phpunit

功能測試

上面做的是單元測試,那假設我們要測試 API 是否符合預期,我們則要使用功能測試。

新增一個 Controller

php artisan make:controller ProductController
class ProductController extends Controller
{
    public function store(Request $request)
    {
        return [
            'id' => (int) $request->id,
            'title' => 'productTitle'
        ];
    }
}

現在新增路由

// api.php
Route::post('products', 'ProductController@store');

接著下指令產生功能測試

php artisan make:test ProductTest

接著嘗試訪問 API,並斷言回傳的 JSON 符合我們的結構

public function testExample()
{
    $pid = 100;
    $response = $this->json('POST', 'api/products', [
        'id' => $pid
    ]);

    // 斷言結構是否相符合
    $response->assertExactJson([
        'id' => $pid,
        'title' => 'productTitle'
    ]);

    // 斷言回傳值是否相等
    $response->assertJson([
        'id' => $pid,
        'title' => true
    ]);
}
php artisan config:clear

(Windows)
vendor\bin\phpunit

(Linux)
vendor/bin/phpunit

如果要在 Request 加入 Header 可以這麼寫

$response = $this->withHeaders([
    'X-Header' => 'Value',
])->json('POST', '/user', ['name' => 'Sally']);

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

若要為 Response 除錯,可以選用添加

$response->dumpHeaders();
$response->dump();

如果使用 phpStorm 進行測試,我們可以透過設定進行測試,請參考這篇

發表迴響