當 API 開發完成後要給 Front-End 串接前還是要先測試一下功能是否正常,否則上線後才發現功能是不能使用的,那不是很糗嗎?這時可以利用瀏覽器直接 call API http://127.0.0.1:8000/api/categories ,此時就可以獲得心中預期的資料了。
此時看一眼這種眼花撩亂的資料格式我都想下班了,那是不是有辦法可以讓系統幫我檢測格式是否正確呢?沒錯,這時候寫測試就可以派上用場了,以下就會開始介紹測試的作用及寫法。
首先常見的測試分為 Unit Test 及 Feature Test 兩種,Unit Test 會針對 Class 層級進行測試,但一般小專案因為商務邏輯相較簡單,通常除了金流、物流有一套共用套件以外較少對 Class 測試,較常用的是 Feature Test 整合性功能測試,以目前的功能就是來試試看 API 是否有回傳正確的資料格式。
在這之前要先為測試準備專用的測試資料庫,待開好新的資料庫命名為 dcat-testing 後為其準備專用 .envcp .env .env.testing
修改設定
APP_ENV=testing
DB_DATABASE=dcat-testing
檢查 test 的設定檔 phpunit.xml
<server name="APP_ENV" value="testing"/>
value 要與 .env.testing 的 APP_ENV 對應到才會正確使用設定
先為新的資料庫設定 migrationphp artisan migration —env=testing
到此準備工作結束,接下來就可以開始為 Category Index 這隻 API 撰寫測試了php artisan make:test Category/IndexTest
要注意所有測試檔案的後綴都要是 Test 才會被系統認定為測試檔案
RefreshDatabase & DatabaseTransactions
建立好測試檔案後即可看到 use Illuminate\Foundation\Testing\RefreshDatabase
, 麻煩將其變更為 use Illuminate\Foundation\Testing\DatabaseTransactions
, 並在 Class 的裡面使用這個 trait , use DatabaseTransactions
。
原因在於每當測試完畢時 RefreshDatabase 會將全部的 Table rollback 在進行 migrate,而 DatabaseTransactions 只會將此次測試所新增的資料 rollback 而已,當測試越來越多時所花的時間就會有很大的差別,敝司有一個裝案將全部的 RefreshDatabase 改為 DatabaseTransactions 測試時間從 2 小時縮減到 15分鐘,可見其差別有多大。
終於可以來到正題了,所謂測試三部曲為:假資料、 call API、 assert
假資料的部分可以使用 DAY16 準備好的 Factory 來完成,並利用 sync 來完成關聯
$categories = Category::factory(3)->create();
$products = Product::factory(3)->create();
foreach ($products as $product) {
$characteristics = Characteristic::factory(2)->create();
$actors = Actor::factory(2)->create();
$video = Video::factory(2)->create([
'product_id' => $product->id,
]);
$product->characteristics()->sync($characteristics->pluck('id'));
$product->actors()->sync($actors->pluck('id'));
}
$categories[0]->products()->sync($products->pluck('id'));
$categories[1]->products()->sync([
$products[0]->id,
$products[1]->id,
]);
$categories[2]->products()->sync([
$products[1]->id,
$products[2]->id,
]);
Call API,並利用 dump 來觀察 API 資料
$response = $this->json('GET', '/api/categories');
$response->dump();
assertStatus 及 assertJsonStructure 是我常用的兩個斷言,使用 * 代表以下的 array 都得符合該格式
$response->assertStatus(200)
->assertJsonStructure([
'*' => [
'id',
'name',
'products' => [
'*' => [
'id',
'name',
'type',
'outline',
'videos' => [
'*' => [
'id',
'path',
'previously',
]
],
'characteristics' => [
'*' => [
'id',
'name',
]
],
'actors' => [
'*' => [
'id',
'name',
]
],
]
],
]
]);
完成之後就可以下指令來測試 API 是否正確了
vendor/bin/phpunit --filter='Category'
如此一來就有最基礎的測試案例了,有時會因為後續的開發會動到重複使用的 Class 而造成舊功能失效時,只要能在上線前跑一次測試及早發現錯誤就可避免線上功能失效,這就是測試的強大所在。一年前的鐵人賽也花了一個篇章來寫關於測試,今年也是如此,這應該代表測試在我心中及一年來的職場經歷中還是很重要的吧。