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
8會員
296內容數
歡迎來到 WilliamP 的沙龍天地,在這裡將與各位讀者探討各種主題,包刮高中數學題庫、PHP開發經驗、LINE聊天機器人開發經驗、書摘筆記等,歡迎交流!
留言0
查看全部
avatar-img
發表第一個留言支持創作者!
WilliamP的沙龍 的其他內容
今天會再與大家介紹幾個資料庫 Assertion 函數,與陣列 Assertion 函數。 與前一篇一樣,以下會提到的資料庫 Assertion 函數,並非 PHPUnit 內建,而是由 Laravel 所擴充,因此需注意是否有確實引用到 use Tests\\TestCase 。最後面介紹的2個
前一天與大家分享了幾個通用型 Assertion 函數,今天來為大家介紹幾個 HTTP 相關的 Assertion 函數吧! 今天要介紹的各函數,其使用方式和前一天所介紹的略有不同。以下所列各函數,皆是基於 HTTP Response 來做驗證測試,因此大家會看到 $response = $thi
前一天我們實作了第一個測試,我們學到了第一個 Assert 函數 assertEquals。 今天讓我們來了解其他常用的 Assert 函數吧! 通用型 Assertion 函數 assertEmpty 函數簽名:assertEmpty(mixed $actual[, string $mess
今天我們來寫第一個單元測試吧! 不過在那之前,先讓我們了解單元測試的「3個A」 單元測試3A 所謂的「3個A」,是指以下三個英文單字: Arrange:初始化工作,如準備假資料 Act:執行測試對象 Assert:驗證結果 一個良好的單元測試案例,應該包含以上的結構, 依序執行 Arra
下載與設定 Laradock 首先,讓我們在Home資料夾下,將 Laradock 下載下來: cd ~ && git clone <https://github.com/Laradock/laradock.git> Laradock 將 Laradock 下載回來後,切換到 Laradock
初遇自動化測試 在數年前,我剛從第一份工作離職,轉職到第二份工作, 新工作是在一個大集團的IT部門,職位是後端工程師。 當時集團正準備導入一個由子公司開發的微服務系統, 使用的技術是PHP 8 及 Laravel 9 因為該系 統在子公司運作得不錯, 因此集團高層想將它擴展成,全集團都可使用的規模
今天會再與大家介紹幾個資料庫 Assertion 函數,與陣列 Assertion 函數。 與前一篇一樣,以下會提到的資料庫 Assertion 函數,並非 PHPUnit 內建,而是由 Laravel 所擴充,因此需注意是否有確實引用到 use Tests\\TestCase 。最後面介紹的2個
前一天與大家分享了幾個通用型 Assertion 函數,今天來為大家介紹幾個 HTTP 相關的 Assertion 函數吧! 今天要介紹的各函數,其使用方式和前一天所介紹的略有不同。以下所列各函數,皆是基於 HTTP Response 來做驗證測試,因此大家會看到 $response = $thi
前一天我們實作了第一個測試,我們學到了第一個 Assert 函數 assertEquals。 今天讓我們來了解其他常用的 Assert 函數吧! 通用型 Assertion 函數 assertEmpty 函數簽名:assertEmpty(mixed $actual[, string $mess
今天我們來寫第一個單元測試吧! 不過在那之前,先讓我們了解單元測試的「3個A」 單元測試3A 所謂的「3個A」,是指以下三個英文單字: Arrange:初始化工作,如準備假資料 Act:執行測試對象 Assert:驗證結果 一個良好的單元測試案例,應該包含以上的結構, 依序執行 Arra
下載與設定 Laradock 首先,讓我們在Home資料夾下,將 Laradock 下載下來: cd ~ && git clone <https://github.com/Laradock/laradock.git> Laradock 將 Laradock 下載回來後,切換到 Laradock
初遇自動化測試 在數年前,我剛從第一份工作離職,轉職到第二份工作, 新工作是在一個大集團的IT部門,職位是後端工程師。 當時集團正準備導入一個由子公司開發的微服務系統, 使用的技術是PHP 8 及 Laravel 9 因為該系 統在子公司運作得不錯, 因此集團高層想將它擴展成,全集團都可使用的規模
你可能也想看
Google News 追蹤
Thumbnail
隨著理財資訊的普及,越來越多台灣人不再將資產侷限於台股,而是將視野拓展到國際市場。特別是美國市場,其豐富的理財選擇,讓不少人開始思考將資金配置於海外市場的可能性。 然而,要參與美國市場並不只是盲目跟隨標的這麼簡單,而是需要策略和方式,尤其對新手而言,除了選股以外還會遇到語言、開戶流程、Ap
Thumbnail
嘿,大家新年快樂~ 新年大家都在做什麼呢? 跨年夜的我趕工製作某個外包設計案,在工作告一段落時趕上倒數。 然後和兩個小孩過了一個忙亂的元旦。在深夜時刻,看到朋友傳來的解籤網站,興致勃勃熬夜體驗了一下,覺得非常好玩,或許有人玩過了,但還是想寫上來分享紀錄一下~
Thumbnail
A/B 測試是一種用來測試不同版本效果的實驗方法,可以用於網站優化、電子郵件行銷和社群媒體行銷中。瞭解 A/B 測試的五個大小技巧,包括明確的測試目標、控制變因、足夠的樣本數、一次只測試一個變因以及追蹤長期表現。在進行網頁優化時,可以將 A/B 測試應用於不同標題、文案、等元素,找出有效的改進方向。
Thumbnail
當我們架好站、WebService測試完,接著就是測試區域網路連線啦~
※ TypeScript範例說明: interface ITest { test1: string test2: number print: (arg: string[]) => boolean } class Test implements ITest { public te
Thumbnail
先前幾篇筆記介紹了網路請求,瀏覽器儲存資料的方式,那麼實務上,前端最常需要發送網路請求的時候,就是透過呼叫 API,去向後端工程師發送/請求資料,所以今天來記錄什麼是 API吧!
Thumbnail
這是一篇很精彩的測試文章喔!
Thumbnail
隨著理財資訊的普及,越來越多台灣人不再將資產侷限於台股,而是將視野拓展到國際市場。特別是美國市場,其豐富的理財選擇,讓不少人開始思考將資金配置於海外市場的可能性。 然而,要參與美國市場並不只是盲目跟隨標的這麼簡單,而是需要策略和方式,尤其對新手而言,除了選股以外還會遇到語言、開戶流程、Ap
Thumbnail
嘿,大家新年快樂~ 新年大家都在做什麼呢? 跨年夜的我趕工製作某個外包設計案,在工作告一段落時趕上倒數。 然後和兩個小孩過了一個忙亂的元旦。在深夜時刻,看到朋友傳來的解籤網站,興致勃勃熬夜體驗了一下,覺得非常好玩,或許有人玩過了,但還是想寫上來分享紀錄一下~
Thumbnail
A/B 測試是一種用來測試不同版本效果的實驗方法,可以用於網站優化、電子郵件行銷和社群媒體行銷中。瞭解 A/B 測試的五個大小技巧,包括明確的測試目標、控制變因、足夠的樣本數、一次只測試一個變因以及追蹤長期表現。在進行網頁優化時,可以將 A/B 測試應用於不同標題、文案、等元素,找出有效的改進方向。
Thumbnail
當我們架好站、WebService測試完,接著就是測試區域網路連線啦~
※ TypeScript範例說明: interface ITest { test1: string test2: number print: (arg: string[]) => boolean } class Test implements ITest { public te
Thumbnail
先前幾篇筆記介紹了網路請求,瀏覽器儲存資料的方式,那麼實務上,前端最常需要發送網路請求的時候,就是透過呼叫 API,去向後端工程師發送/請求資料,所以今天來記錄什麼是 API吧!
Thumbnail
這是一篇很精彩的測試文章喔!