在前兩篇文章中,我們先談了為什麼「還沒開始單元測試的你一定很忙」,並介紹了如何使用純粹的 PHPUnit 從 0 到 1 寫出第一支測試。
現在,我們要走得更深、更實務:如果你是使用 Laravel 進行開發,那 Laravel 本身就整合了 PHPUnit,並且提供了許多「框架級」的測試輔助工具,讓測試前後端互動、資料庫操作、使用者身份驗證等都更加便捷。
本篇目標:帶領你認識 Laravel 的測試環境、常見的測試寫法,以及在 Laravel 專案中快速上手的技巧,讓測試不再只限於「函式級測試」,而是能全面涵蓋路由、Controller、資料庫、認證機制等。
以下使用的版本是 Laravel 10
測試目錄:Laravel 在專案根目錄下預設有 tests/
資料夾,一般會依照功能類型(Feature、Unit 等)進行區分。
Laravel 預設的測試目錄結構如下:
tests/
├── Feature/
│ └── ExampleTest.php
├── Unit/
│ └── ExampleTest.php
└── TestCase.php
你可以根據專案需求進一步擴展這個結構,例如:
tests/
├── Feature/
│ ├── Auth/
│ │ └── LoginTest.php
│ ├── ArticleTest.php
├── Unit/
│ ├── Models/
│ │ └── ArticleTest.php
└── TestCase.php
phpunit.xml
:Laravel 預設會有一個 phpunit.xml
檔案,用來指定測試設定(例如測試資料庫的連線設定、Bootstrap 路徑)。
為避免測試影響開發資料,建議設定一個測試專用資料庫:
在 .env.testing
配置:
DB_CONNECTION=mysql
DB_DATABASE=testing_db
DB_USERNAME=root
DB_PASSWORD=
在 phpunit.xml
指定環境變數:
<server name="APP_ENV" value="testing"/>
執行測試:在 Laravel 專案中,你可以直接使用
或者依舊可以執行:
這兩種方式都是「同一套」,只是 artisan test
會多一些 Laravel 特有的報告樣式與懶人指令。
php artisan test
vendor/bin/phpunit
雖然 Laravel 已經幫我們「預設」了不少東西,但並不是每個專案的架構都一樣。你仍可以自訂測試目錄、切分更多測試子資料夾。這取決於團隊規模與習慣。
在 Laravel 專案中,最常見的測試場景之一,就是測試「透過 HTTP 路由呼叫 Controller 是否能得到預期結果」。Laravel 提供了一套流暢的 API 讓我們可以撰寫這類測試。
假設我們要測試一個簡單的文章列表功能(ArticleController@index
)。我們可以在 tests/Feature/ArticleTest.php
建立測試檔:
<?php
namespace Tests\\Feature;
use Tests\\TestCase;
use Illuminate\\Foundation\\Testing\\RefreshDatabase;
use App\\Models\\Article;
class ArticleTest extends TestCase
{
use RefreshDatabase;
public function testArticleIndexReturnsData()
{
// Arrange: 建立測試用資料
Article::factory()->count(3)->create();
// Act: 透過 GET 方式請求 /articles
$response = $this->get('/articles');
// Assert: 驗證回應狀態碼與資料
$response->assertStatus(200);
$response->assertSeeText('Title'); // 假設 Blade 模板會顯示文章標題
}
}
$this->get('/articles')
:模擬一個對路由 /articles
的 GET 請求,並獲得回應。assertStatus(200)
:斷言 HTTP 回應狀態碼是否是 200 OK。assertSeeText('Title')
:檢查回應的內容中,是否包含「Title」字串。這樣就能確保我們在 Controller / Blade 中渲染的資料確實包含在回應中。
RefreshDatabase
的作用use RefreshDatabase;
:每次測試執行前後,會自動「回復資料庫狀態」,通常是透過跑 migration 讓資料庫保持乾淨,避免測試彼此干擾。透過具體的例子與方法呼叫,證明 Laravel Test 能輕鬆測試 Controller 與資料庫互動。只要能舉出一個實作成功的案例,就證明了它的可行性與便利性。
除了直接透過路由做測試,你也可以針對 Model 的邏輯與資料庫互動進行更細微的測試。
<?php
namespace Tests\\Unit;
use Tests\\TestCase;
use App\\Models\\Article;
use Illuminate\\Foundation\\Testing\\RefreshDatabase;
class ArticleModelTest extends TestCase
{
use RefreshDatabase;
public function testArticleCreation()
{
$article = Article::factory()->create([
'title' => 'Test Title',
]);
// 斷言:資料庫有這筆資料
$this->assertDatabaseHas('articles', [
'title' => 'Test Title',
]);
// 斷言:這筆資料有自動產生的 ID
$this->assertNotNull($article->id);
}
}
assertDatabaseHas()
:檢查資料表中是否存在指定條件的紀錄。actingAs()
在實際應用中,很多功能都需要使用者登入、角色驗證等。Laravel 測試中提供了 actingAs()
讓你能模擬使用者身份。
public function testUserCanSeeProfilePage()
{
$user = User::factory()->create();
// 模擬該用戶登入
$response = $this->actingAs($user)->get('/profile');
$response->assertStatus(200);
$response->assertSeeText($user->name);
}
這樣就能在測試時,直接測試「某用戶」存取某頁面是否正確,而不用真的在瀏覽器裡點擊登入流程。
json()
與 API 測試$this->json('POST', '/api/articles', [...])
,並用 assertJson()
、assertJsonFragment()
等方法做 JSON 回應檢查。上面列舉的只是常見的測試技巧,每個專案可能會遇到更複雜的情境(例如多層次的前後端整合、大量第三方 API 介接等)。Laravel 的測試工具箱夠豐富,但仍需配合更完整的設計與規劃才能覆蓋所有情境。
php artisan make:test MyFeatureTest --unit
可以快速生成測試檔案,省去手動建立檔案、引用命名空間的麻煩。php artisan test
,保持測試「綠燈」狀態;一旦出現紅燈就立刻修正。透過持續跑測試,你可以很明顯感受到「有測試」帶來的安心感,一旦程式邏輯被破壞,測試會第一時間告訴你,比人肉檢查更有效率。
在 Laravel 生態系中,撰寫測試不僅能驗證「程式是否正常」,也能檢查「介面與資料庫整合度」、「使用者角色驗證是否正確」、「多步驟流程互動」等等。
這些功能在純粹的 PHPUnit 環境下也做得到,但 Laravel 提供了大量的快捷方法與輔助工具,讓你不必從頭自己組裝一堆測試工具。
到這裡,我們已經能運用 Laravel Test 基本的實作技巧。但測試除了技術層面,還有一個更重要的部分——如何將測試思維拓展到團隊層面?
在下一篇,我們將探討「測試的思維轉換:從個人到團隊的測試策略」。如何讓整個團隊一起落實測試,並在專案合作中形塑出穩固且有效率的開發流程?敬請期待!
tests/
資料夾、phpunit.xml
、artisan test
。get()
, post()
等方法與 assertStatus()
, assertSeeText()
。assertDatabaseHas()
與 RefreshDatabase
等工具,確保資料庫狀態一致性。actingAs()
輕鬆模擬登入。透過這些範例,希望你能漸漸培養在 Laravel 中「自然而然就想寫測試」的好習慣。下篇文章,讓我們進一步聊聊如何把測試從個人的行為,擴展到整個團隊的合作策略!