PHPUnit 自動化測試大作戰【CH07】

更新於 發佈於 閱讀時間約 19 分鐘

在前幾篇文章中,我們介紹了測試3A原則,也介紹了許多 Assertion 函數,今天就讓我們實際演練吧!

過去的經驗中,最常用自動化測試來測式的對象,大概就是API了,而前後端分離也是目前 Web 開發界常用的模式,因此我們就以 API 測試來演練吧!

驗證HTTP Status Code

HTTP Status Code 的驗證,應該是最常遇到的 API 測試情境了,其實前面的 Assertion 函數範例中也有展示部分使用方式了,這次讓我們更完整地演練吧!

提醒一點,由於以下的測試會牽涉到資料庫,因此大家要再檢查一下 phpunit.xml 中的資料庫連線設定是否已填上,詳情可參考前Day 6文章內容。

另值得一提的是,為了方便取用路由路徑,在設置路由時,通常都會將路由命名。

案例1:200 — 索取使用者資料

  • routes/api.php
<?php

use App\Models\User;

use Illuminate\Http\Request;

use Illuminate\Support\Facades\Route;

Route::get('/users', function (Request $request) {

$users = User::all();

return response()->json([

'users' => $users,

]);})->name('get.user.list');
  • tests/Feature/HttpStatusCodeTest.php
<?php

namespace Tests\Feature;

use Illuminate\Foundation\Testing\RefreshDatabase;

use Tests\TestCase;

class HttpStatusCodeTest extends TestCase{

use RefreshDatabase;

public function testCanGetUserListWhenEmpty() {

$response = $this->get(route('get.user.list'));

$response->assertOk();

// 也可以寫成以下串聯寫法

$this->get(route('get.user.list'))

->assertOk();

}}

在以上程式碼中, users 資料表尚無任何User資料,但取得User清單的端點也應該要能正常回應,透過以上測試程式碼,可以驗證此行為是否正常運作。

案例2:404 — 索取不存在之使用者資料

  • routes/api.php
<?php

use App\Models\User;

use Illuminate\Http\Request;

use Illuminate\Support\Facades\Route;

Route::get('/users/{id}', function (Request $request, $id) {

$user = User::find($id);

if (empty($user)) {

return response()->json([

'error' => 'Not Found',

], 404);

} return response()->json([

'user' => $user,

]);})->where('id', '[0-9]?')->name('get.user');
  • tests/Feature/HttpStatusCodeTest.php
<?php

namespace Tests\Feature;

use Illuminate\Foundation\Testing\RefreshDatabase;

use Tests\TestCase;

class HttpStatusCodeTest extends TestCase{

use RefreshDatabase;

public function testCanGetNotFoundWhenNoGivenUser() {

$response = $this->get(route('get.user', ['id' => 1,]));

$response->assertNotFound();

// 也可以寫成以下串聯寫法

$this->get(route('get.user', ['id' => 1,]))

->assertNotFound();

}}

在以上程式碼中, users 資料表尚無任何User資料,因此當嘗試取得 id=1 之 User 資源時,應會找不到,也就是404,透過以上測試程式碼,可以驗證此行為是否正常運作。

案例3:422 — 請求驗證未通過

  • routes/api.php
<?php

use App\Models\User;

use Illuminate\Http\Request;

use Illuminate\Support\Facades\Route;

Route::post('/users', function (Request $request) {

$request->validate([

'name' => 'required|string',

'email' => 'required|email',

'password' => 'required|string',

]); $user = User::create($request->all());

return response()->json([

'user' => $user,

]);})->name('store.user');
  • tests/Feature/HttpStatusCodeTest.php
<?php

namespace Tests\Feature;

use Illuminate\Foundation\Testing\RefreshDatabase;

use Tests\TestCase;

class HttpStatusCodeTest extends TestCase{

use RefreshDatabase;

public function testCanResponseUnprocessableWhenInvalidRequest() {

$response = $this->post(

route('store.user'),

['name' => ''],

['Accept' => 'application/json']

); $response->assertUnprocessable();

// 也可以寫成以下串聯寫法

$this->post(

route('store.user'),

['name' => ''],

['Accept' => 'application/json']

) ->assertUnprocessable();

}}

在以上程式碼中, 我們建立了一個可以建立 User 資料的路由端點,與實作建立資料流程,並在這當中建立了驗證請求資料的邏輯,而在下方的測試案例中,我們測試了「當請求內容有缺失時,應回應 422 Unprocessable Entity」這個行為是否正常運作。

驗證Response JSON

除了前面介紹的 HTTP Status Code 驗證,在測試 API 時,另一個常常需要做驗證的部分,應該就是回應JSON的內容本身了,以下就讓我們來看看實例吧!

案例1:驗證回應JSON內容

  • routes/api.php
<?php

use Illuminate\Http\Request;

use Illuminate\Support\Facades\Route;

Route::get('/users', function (Request $request) {

// 這邊先用假的 User 資料

$users = [

[ 'id' => 1,

'name' => 'name1',

'email' => 'user1@email.com',

], [ 'id' => 1,

'name' => 'name1',

'email' => 'user1@email.com',

], ]; return response()->json([

'users' => $users,

]);})->name('get.user.list');
  • tests/Feature/HttpStatusCodeTest.php
<?php

namespace Tests\Feature;

use Illuminate\Foundation\Testing\RefreshDatabase;

use Tests\TestCase;

class HttpStatusCodeTest extends TestCase{

use RefreshDatabase;

public function testCanGetUserJson() {

$response = $this->get(route('get.user.list'));

$response->assertJson([

'users' => [

[ 'id' => 1,

'name' => 'name1',

'email' => 'user1@email.com',

], [ 'id' => 1,

'name' => 'name1',

'email' => 'user1@email.com',

], ] ]); // 也可以寫成以下串聯寫法

$this->get(route('get.user.list'))

->assertJson([

'users' => [

[ 'id' => 1,

'name' => 'name1',

'email' => 'user1@email.com',

], [ 'id' => 1,

'name' => 'name1',

'email' => 'user1@email.com',

], ] ]); }}

在以上程式碼中, 我們建立了一個可以取得 User 清單的端點,並且驗證在呼叫此 API 後,其回應的JSON是否符合預期。

案例2:驗證回應JSON結構

  • routes/api.php
<?php

use Illuminate\Http\Request;

use Illuminate\Support\Facades\Route;

Route::get('/users', function (Request $request) {

// 這邊先用假的 User 資料

$users = [

[ 'id' => 1,

'name' => 'name1',

'email' => 'user1@email.com',

], [ 'id' => 1,

'name' => 'name1',

'email' => 'user1@email.com',

], ]; return response()->json([

'users' => $users,

]);})->name('get.user.list');
  • tests/Feature/HttpStatusCodeTest.php
<?php

namespace Tests\Feature;

use Illuminate\Foundation\Testing\RefreshDatabase;

use Tests\TestCase;

class HttpStatusCodeTest extends TestCase{

use RefreshDatabase;

public function testCanGetUserJsonStructure() {

$response = $this->get(route('get.user.list'));

// '*' 代表是每陣列元素

// 此寫法相當於驗證 'users' 是一個陣列

// 每個陣列元素是一個物件

// 每個物件有 id, name, email 這幾個欄位

$response->assertJsonStructure([

'users' => [

'*' => [

'id',

'name',

'email'

], ], ]); // 也可以寫成以下串聯寫法

$this->get(route('get.user.list'))

->assertJsonStructure([

'users' => [

'*' => [

'id',

'name',

'email'

], ], ]); }}

另一種常見的情況,是只驗證 JSON 結構,而略過驗證 JSON 的鍵與值。

以上就是今天的介紹,大家可以多加練習看看!

下一篇讓我們來練習資料庫測試吧!

如果您喜歡這篇文章,歡迎加入追蹤以接收新文章通知 😄

本系列文章目錄

留言
avatar-img
留言分享你的想法!
avatar-img
WilliamP的沙龍
13會員
473內容數
歡迎來到 WilliamP 的沙龍天地,在這裡將與各位讀者探討各種主題,包刮高中數學題庫、PHP開發經驗、LINE聊天機器人開發經驗、書摘筆記等,歡迎交流!
WilliamP的沙龍的其他內容
2023/12/18
在前一篇文章中,我們探討了多重資料庫連線情境下,Model 及 Database Assertion 的應對方式,不過實際上筆者認為比較有難度的,其實是 Migration 應對方式。 今天就讓我們來探討這部分吧! Migration 應對方式 對於多重資料庫連線這種情境,筆者實務上做過的對應
2023/12/18
在前一篇文章中,我們探討了多重資料庫連線情境下,Model 及 Database Assertion 的應對方式,不過實際上筆者認為比較有難度的,其實是 Migration 應對方式。 今天就讓我們來探討這部分吧! Migration 應對方式 對於多重資料庫連線這種情境,筆者實務上做過的對應
2023/12/18
今天讓我們探討「缺乏 Migration Files 與 Factory Files」的 Legacy 情境吧! 很多時候我們會遇到沒有 Migration Files 或 Factory Files 的 Legacy Codebase,原因大概有以下幾種: 該程式庫原本不是以 Laravel
2023/12/18
今天讓我們探討「缺乏 Migration Files 與 Factory Files」的 Legacy 情境吧! 很多時候我們會遇到沒有 Migration Files 或 Factory Files 的 Legacy Codebase,原因大概有以下幾種: 該程式庫原本不是以 Laravel
2023/12/18
在實務情境上,常會有在單一專案程式庫中,存取多個不同資料庫的使用情境,在這種情況下,我們通常會設置多個資料庫連線(Database Connection)設定。 在平常開發使用設很方便,但要做測試時就會發現一些問題: 在測試程式碼或 Seeder 中調用 factory() 時,都是在預設連線資
2023/12/18
在實務情境上,常會有在單一專案程式庫中,存取多個不同資料庫的使用情境,在這種情況下,我們通常會設置多個資料庫連線(Database Connection)設定。 在平常開發使用設很方便,但要做測試時就會發現一些問題: 在測試程式碼或 Seeder 中調用 factory() 時,都是在預設連線資
看更多
你可能也想看
Thumbnail
「欸!這是在哪裡買的?求連結 🥺」 誰叫你太有品味,一發就讓大家跟著剁手手? 讓你回購再回購的生活好物,是時候該介紹出場了吧! 「開箱你的美好生活」現正召喚各路好物的開箱使者 🤩
Thumbnail
「欸!這是在哪裡買的?求連結 🥺」 誰叫你太有品味,一發就讓大家跟著剁手手? 讓你回購再回購的生活好物,是時候該介紹出場了吧! 「開箱你的美好生活」現正召喚各路好物的開箱使者 🤩
Thumbnail
※ 什麼是Web API API 就是後端開出來讓前端來用的介面,讓前端與後端可以溝通。 API流程: 終端使用者用任何一種裝置進入瀏覽器。 瀏覽器透過 API 向後端發出請求,請求查詢或修改資料。 後端透過 API 收到前端的請求後,取得資料並回應給前端。 前端渲染畫面,終端使用者
Thumbnail
※ 什麼是Web API API 就是後端開出來讓前端來用的介面,讓前端與後端可以溝通。 API流程: 終端使用者用任何一種裝置進入瀏覽器。 瀏覽器透過 API 向後端發出請求,請求查詢或修改資料。 後端透過 API 收到前端的請求後,取得資料並回應給前端。 前端渲染畫面,終端使用者
Thumbnail
在這一章中,我們探討了 PHP 中的函數,包括函數的基本結構、不同的函數定義方式(如函數聲明、函數表達式、箭頭函數和匿名函數)以及如何呼叫函數。我們還討論了函數的參數處理方式,包括單個參數、多個參數、預設參數值和剩餘參數。此外,我們還介紹了函數的返回值,包括返回單個值、返回物件和返回函數的情況。
Thumbnail
在這一章中,我們探討了 PHP 中的函數,包括函數的基本結構、不同的函數定義方式(如函數聲明、函數表達式、箭頭函數和匿名函數)以及如何呼叫函數。我們還討論了函數的參數處理方式,包括單個參數、多個參數、預設參數值和剩餘參數。此外,我們還介紹了函數的返回值,包括返回單個值、返回物件和返回函數的情況。
Thumbnail
在這一章中,我們介紹了PHP中的流程控制語句,包括if、else if、else、三元運算子、switch語句、for迴圈、foreach迴圈、while迴圈、do-while迴圈、循環嵌套以及控制迴圈的語句如break、continue、goto和return。
Thumbnail
在這一章中,我們介紹了PHP中的流程控制語句,包括if、else if、else、三元運算子、switch語句、for迴圈、foreach迴圈、while迴圈、do-while迴圈、循環嵌套以及控制迴圈的語句如break、continue、goto和return。
Thumbnail
本章節旨在介紹如何在不同操作系統上安裝和配置PHP環境,並使用命令行工具進行基礎操作。此外,還介紹了使用Visual Studio Code進行PHP開發的步驟,包括安裝擴展和設置調試環境。
Thumbnail
本章節旨在介紹如何在不同操作系統上安裝和配置PHP環境,並使用命令行工具進行基礎操作。此外,還介紹了使用Visual Studio Code進行PHP開發的步驟,包括安裝擴展和設置調試環境。
Thumbnail
在本節中,我們介紹了PHP的基本語法,包括如何在HTML中嵌入PHP代碼,PHP腳本的執行順序,以及多種註解方式。我們還學習了如何定義和使用變數,包括單個變數和多個變數的賦值方法。這些基礎知識將幫助你開始使用PHP進行Web開發。
Thumbnail
在本節中,我們介紹了PHP的基本語法,包括如何在HTML中嵌入PHP代碼,PHP腳本的執行順序,以及多種註解方式。我們還學習了如何定義和使用變數,包括單個變數和多個變數的賦值方法。這些基礎知識將幫助你開始使用PHP進行Web開發。
Thumbnail
本文介紹了在網站開發中如何運用狀態機的原則和設計方法。通過具體案例分析,以及狀態和數據的區分,詳細介紹了狀態機的設計原則和應用。讀者可以通過本文瞭解如何將狀態機應用於實際的網站開發中。
Thumbnail
本文介紹了在網站開發中如何運用狀態機的原則和設計方法。通過具體案例分析,以及狀態和數據的區分,詳細介紹了狀態機的設計原則和應用。讀者可以通過本文瞭解如何將狀態機應用於實際的網站開發中。
Thumbnail
當我們架好站、WebService測試完,接著就是測試區域網路連線啦~
Thumbnail
當我們架好站、WebService測試完,接著就是測試區域網路連線啦~
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News