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

更新於 2024/12/17閱讀時間約 14 分鐘

今天要來為大家介紹 Storage Mocking 及 HTTP Mocking!

Storage Mocking 函數

  • Storage::fake():當我們希望在執行測試目標行為時,想驗證 Storage 各類行為是否符合預期,但又不要真的增刪改檔案時,可在測試程式碼中呼叫此函數。
  • UploadedFile::fake():這個函數可以模擬出一個已上傳的檔案。
  • Storage::disk($disk)->assertExists():可驗證指定的 $disk 內,是否有指定檔案存在。需在執行 Storage::fake() 後方可使用。
  • Storage::disk(disk)->assertMissing():可驗證指定的 $disk 內,是否無指定檔案存在。需在執行 Storage::fake() 後方可使用。

Storage Mocking 範例:上傳檔案

測試目標:上傳檔案端點

  • config/filesystems.php
<?php

return [

'default' => env('FILESYSTEM_DISK', 'photos'),

'disks' => [

'photos' => [

'driver' => 'local',

'root' => storage_path('app/photos'),

'throw' => false,

], ],];
  • routes/api.php
<?php

use Illuminate\Http\Request;

use Illuminate\Support\Facades\Route;

use Illuminate\Support\Facades\Storage;

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

$photo = $request->file('photo');

if (empty($photo)) {

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

} Storage::disk('photos')->put('photo.jpg', $photo);

return response()->json('');

})->name('upload.photo');
  • 測試程式碼:
<?php

namespace Tests\Feature;

use Illuminate\Http\UploadedFile;

use Illuminate\Support\Facades\Storage;

use Tests\TestCase;

class StorageTest extends TestCase{

public function testUploadFileSuccess() {

Storage::fake('photos');

$response = $this->json('POST', route('upload.photo'), [

'photo' => UploadedFile::fake()->image('p.jpg'),

]); Storage::disk('photos')->assertExists('photo.jpg');

} public function testUploadFileFailed() {

Storage::fake('photos');

$response = $this->json('POST', route('upload.photo'), [

'p' => UploadedFile::fake()->image('p.jpg'),

]); Storage::disk('photos')->assertMissing('photo.jpg');

}}

以上測試程式碼,測試了 2 種測試案例:

  • testUploadFileSuccess():在這個測試案例函數中,我們驗證了當上傳照片端點被請求,且檔案內容有被放置在指定的欄位時,上傳之檔案將存在於 photos 這個 $disk中。
  • testUploadFileFailed():在這個測試案例函數中,我們驗證了當上傳照片端點被請求,且檔案內容沒有被放置在指定的欄位時,上傳之檔案將不存在於 photos 這個 $disk中。

接著我們來看看 HTTP Mocking 吧!

HTTP Mocking 函數

Http::fake():當預進行測試的的測試目標行為,其內部有向外部發送 API 請求,但不希望在執行測試時,真的向外部發送 API 請求時,可在測試程式碼中呼叫此函數。

與其他 fake() 函數不同的是,HTTP Mocking 主要是設定在 Http::fake() 這個函數:

Http::fake([

'<https://weather.tw/taiwan>' => Http::response(

[ 'rain' => 0.8,

'temp_high' => 27,

'temp_low' => 23,

], 200,

[] ),]);

由上面的程式碼可看出,會吃一個陣列,而這個陣列就是預期中要模擬的「呼叫外部API」的行為及其回應。

HTTP Mocking 範例:統整外部天氣資料

測試目標:呼叫氣象局API索取天氣資料並統整

  • routes/api.php
<?php

use Illuminate\Http\Request;

use Illuminate\Support\Facades\Http;

use Illuminate\Support\Facades\Route;

Route::get('rain-chance', function (Request $request) {

$response = Http::get('https://weather.tw/taiwan');

// 這邊我們先假設真的有這個網站

// 且其回應值如下:

// {"rain":0.8,"temp_high":27,"temp_low":23}

if ($response->status() !== 200) {

return response()->json(['Error' => 'Failed to get the data of rain chance.']);

} $rainChance = $response->json('rain');

if (!is_float($rainChance)) {

return response()->json(['Error' => 'Failed to get the data of rain chance.']);

} return response()->json(['rain_chance' => $rainChance]);

})->name('get.rain-chance');
  • 測試程式碼:
<?php

namespace Tests\Feature;

use Illuminate\Http\UploadedFile;

use Illuminate\Support\Facades\Http;

use Illuminate\Support\Facades\Storage;

use Tests\TestCase;

class HttpTest extends TestCase{

public function testGetRainChanceCanWorkWhenGetValidData() {

Http::fake([

'https://weather.tw/taiwan' => Http::response(

[ 'rain' => 0.8,

'temp_high' => 27,

'temp_low' => 23,

], 200,

[] ), ]); $this->get(route('get.rain-chance'))

->assertOk()

->assertJsonStructure(['rain_chance']);

} public function testGetRainChanceCanWorkWhenGetInvalidData() {

Http::fake([

'https://weather.tw/taiwan' => Http::response(

[ 'temp_high' => 27,

'temp_low' => 23,

], 200,

[] ), ]); $this->get(route('get.rain-chance'))

->assertOk()

->assertJson(['Error' => 'Failed to get the data of rain chance.']);

} public function testGetRainChanceCanWorkWhenGet500() {

Http::fake([

'https://weather.tw/taiwan' => Http::response(

'',

500,

[] ), ]); $this->get(route('get.rain-chance'))

->assertOk()

->assertJson(['Error' => 'Failed to get the data of rain chance.']);

}}

以上測試程式碼,測試了 3 種測試案例:

  • testGetRainChanceCanWorkWhenGetValidData():在這個測試案例函數中,我們驗證了當降雨機率端點被請求,且外部 API 回應正常時,我們的 API 應當有的正常回應。
  • testGetRainChanceCanWorkWhenGetInvalidData():在這個測試案例函數中,我們驗證了當降雨機率端點被請求,且外部 API 回應缺少必要欄位時,我們的 API 應當有的回應(包含錯誤訊息)
  • testGetRainChanceCanWorkWhenGet500():在這個測試案例函數中,我們驗證了當降雨機率端點被請求,且外部 API 回應500時,我們的 API 應當有的回應(包含錯誤訊息)。

以上就是今天的介紹囉!

之後讓我們來看看覆蓋率報告以及 phpunit.xml 吧!

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

參考資料

本系列文章目錄

avatar-img
8會員
270內容數
歡迎來到 WilliamP 的沙龍天地,在這裡將與各位讀者探討各種主題,包刮高中數學題庫、PHP開發經驗、LINE聊天機器人開發經驗、書摘筆記等,歡迎交流!
留言0
查看全部
avatar-img
發表第一個留言支持創作者!
WilliamP的沙龍 的其他內容
今天來看 Queue Mocking 吧! Queue Mocking 函數 Queue::fake():當我們希望在執行測試目標行為時,想驗證某個 Job 類別是否有被派送至佇列中,但又不要真的觸發 Job 入列時,可在測試程式碼中呼叫此函數。 Queue::assertPushed():可
今天來看 Mail Mocking 吧! Mail Mocking 函數 Mail::fake():當我們希望在執行測試目標行為時, 想驗證是否有觸發到發送 Email ,但又不要真的觸發 Email 的寄送時,可在測試程式碼中呼叫此函數。 Mail::assertSent():可驗證指定的
今天我們會接續環繞著 「Mocking」 這個主題。 在 Laravel 中,有幾個類別的 Mocking 方式,與前兩天所介紹的方式有所不同,在這次的系列文章中,會和大家介紹 Event、Mail、Queue、Storage、HTTP 這幾個類別的特殊 Mocking 方式。 今天就先來看 E
今天讓我們回顧一下前一天的 Mocking 初體驗吧! Mocking 初體驗回顧 app/Repositories/UserRepository.php <?php namespace App\Repositories; use App\Models\User; class UserR
今天我們來聊聊「Mocking」吧! 何為 Mocking & 為何 Mocking 所謂的 Mocking,是指用各種方式來模擬它原本的行為與功能,藉此將我們要測試的對象,與其相依的外部服務「隔離」。簡單來說,就是做一個外部服務的「仿冒品」。這裡的外部服務,可以是其他類別函數、外部API、檔案
今天讓我們來看看播種器吧! 什麼是播種器 播種器 (Seeder) 是 Laravel 提供的一個批次建立測試資料的功能,可以讓我們將建立測試資料的邏輯,統一寫在一個播種器類別中,方便我們重複調用以建立否些特定資料。 播種器實例 建立播種器指令 php artisan make:seede
今天來看 Queue Mocking 吧! Queue Mocking 函數 Queue::fake():當我們希望在執行測試目標行為時,想驗證某個 Job 類別是否有被派送至佇列中,但又不要真的觸發 Job 入列時,可在測試程式碼中呼叫此函數。 Queue::assertPushed():可
今天來看 Mail Mocking 吧! Mail Mocking 函數 Mail::fake():當我們希望在執行測試目標行為時, 想驗證是否有觸發到發送 Email ,但又不要真的觸發 Email 的寄送時,可在測試程式碼中呼叫此函數。 Mail::assertSent():可驗證指定的
今天我們會接續環繞著 「Mocking」 這個主題。 在 Laravel 中,有幾個類別的 Mocking 方式,與前兩天所介紹的方式有所不同,在這次的系列文章中,會和大家介紹 Event、Mail、Queue、Storage、HTTP 這幾個類別的特殊 Mocking 方式。 今天就先來看 E
今天讓我們回顧一下前一天的 Mocking 初體驗吧! Mocking 初體驗回顧 app/Repositories/UserRepository.php <?php namespace App\Repositories; use App\Models\User; class UserR
今天我們來聊聊「Mocking」吧! 何為 Mocking & 為何 Mocking 所謂的 Mocking,是指用各種方式來模擬它原本的行為與功能,藉此將我們要測試的對象,與其相依的外部服務「隔離」。簡單來說,就是做一個外部服務的「仿冒品」。這裡的外部服務,可以是其他類別函數、外部API、檔案
今天讓我們來看看播種器吧! 什麼是播種器 播種器 (Seeder) 是 Laravel 提供的一個批次建立測試資料的功能,可以讓我們將建立測試資料的邏輯,統一寫在一個播種器類別中,方便我們重複調用以建立否些特定資料。 播種器實例 建立播種器指令 php artisan make:seede
你可能也想看
Google News 追蹤
Thumbnail
*合作聲明與警語: 本文係由國泰世華銀行邀稿。 證券服務係由國泰世華銀行辦理共同行銷證券經紀開戶業務,定期定額(股)服務由國泰綜合證券提供。   剛出社會的時候,很常在各種 Podcast 或 YouTube 甚至是在朋友間聊天,都會聽到各種市場動態、理財話題,像是:聯準會降息或是近期哪些科
在前一篇文章中,我們探討了多重資料庫連線情境下,Model 及 Database Assertion 的應對方式,不過實際上筆者認為比較有難度的,其實是 Migration 應對方式。 今天就讓我們來探討這部分吧! Migration 應對方式 對於多重資料庫連線這種情境,筆者實務上做過的對應
今天讓我們探討「缺乏 Migration Files 與 Factory Files」的 Legacy 情境吧! 很多時候我們會遇到沒有 Migration Files 或 Factory Files 的 Legacy Codebase,原因大概有以下幾種: 該程式庫原本不是以 Laravel
在實務情境上,常會有在單一專案程式庫中,存取多個不同資料庫的使用情境,在這種情況下,我們通常會設置多個資料庫連線(Database Connection)設定。 在平常開發使用設很方便,但要做測試時就會發現一些問題: 在測試程式碼或 Seeder 中調用 factory() 時,都是在預設連線資
今天就讓我們依照前一天的情境題,來撰寫測試案例函數吧! 這次同樣地,先讓我們規畫擬訂測試案例: 測試案例 使用者註冊: 使用者可送出註冊資料,系統將建立使用者資料,並送出含有專屬驗證連結之驗證信,當此驗證連結被開啟後,將讓使用者轉為已驗證狀態 請求錯誤的驗證連結: 錯誤的驗證連結被開啟後
前兩天,我們探討了「網站文章」的情境題;今明兩天,就讓我們探討另一個情境題「會員註冊」吧! 這邊我們同樣假設網站是採前後端分離的設計,因此我們就專注在測試 API 的部分,不過會多一個「註冊驗證信」的部分要實作與做測試驗證。 使用案例 使用者可填寫註冊資料後送出資料。 使用者可收到註冊驗證信
Thumbnail
練習 PHPUnit 測試的撰寫,依序創建Controller、Service,並針對計算邏輯進行單元測試的練習。
Thumbnail
在 Laravel 中的測試中,PHPUnit 和 Mockery 都可以用來創建測試替身(test double),但它們有不同的方式和功能,以下簡單介紹兩種寫法方式。
前言 基本準備差不多了,也能跑自己的測試,再來就是關於測試腳本的核心:元素定位跟動作,本篇會著重介紹 XPATH 定位的部分
Thumbnail
前言 上篇我們成功執行第一個測試案例,從 Python 腳本透過 Appium 控制模擬器點選設定中的電池,下個問題就是怎麼找元件,這時候就要請出 Appium Inspector 了
前言 經過五個小單元的準備,終於可以開始跑第一個測試了,Appium 本身是個工具,可以搭配各種語言,這邊選擇 Python 作為測試腳本語言,以便之後跟 Robot Framework 串接。
Thumbnail
*合作聲明與警語: 本文係由國泰世華銀行邀稿。 證券服務係由國泰世華銀行辦理共同行銷證券經紀開戶業務,定期定額(股)服務由國泰綜合證券提供。   剛出社會的時候,很常在各種 Podcast 或 YouTube 甚至是在朋友間聊天,都會聽到各種市場動態、理財話題,像是:聯準會降息或是近期哪些科
在前一篇文章中,我們探討了多重資料庫連線情境下,Model 及 Database Assertion 的應對方式,不過實際上筆者認為比較有難度的,其實是 Migration 應對方式。 今天就讓我們來探討這部分吧! Migration 應對方式 對於多重資料庫連線這種情境,筆者實務上做過的對應
今天讓我們探討「缺乏 Migration Files 與 Factory Files」的 Legacy 情境吧! 很多時候我們會遇到沒有 Migration Files 或 Factory Files 的 Legacy Codebase,原因大概有以下幾種: 該程式庫原本不是以 Laravel
在實務情境上,常會有在單一專案程式庫中,存取多個不同資料庫的使用情境,在這種情況下,我們通常會設置多個資料庫連線(Database Connection)設定。 在平常開發使用設很方便,但要做測試時就會發現一些問題: 在測試程式碼或 Seeder 中調用 factory() 時,都是在預設連線資
今天就讓我們依照前一天的情境題,來撰寫測試案例函數吧! 這次同樣地,先讓我們規畫擬訂測試案例: 測試案例 使用者註冊: 使用者可送出註冊資料,系統將建立使用者資料,並送出含有專屬驗證連結之驗證信,當此驗證連結被開啟後,將讓使用者轉為已驗證狀態 請求錯誤的驗證連結: 錯誤的驗證連結被開啟後
前兩天,我們探討了「網站文章」的情境題;今明兩天,就讓我們探討另一個情境題「會員註冊」吧! 這邊我們同樣假設網站是採前後端分離的設計,因此我們就專注在測試 API 的部分,不過會多一個「註冊驗證信」的部分要實作與做測試驗證。 使用案例 使用者可填寫註冊資料後送出資料。 使用者可收到註冊驗證信
Thumbnail
練習 PHPUnit 測試的撰寫,依序創建Controller、Service,並針對計算邏輯進行單元測試的練習。
Thumbnail
在 Laravel 中的測試中,PHPUnit 和 Mockery 都可以用來創建測試替身(test double),但它們有不同的方式和功能,以下簡單介紹兩種寫法方式。
前言 基本準備差不多了,也能跑自己的測試,再來就是關於測試腳本的核心:元素定位跟動作,本篇會著重介紹 XPATH 定位的部分
Thumbnail
前言 上篇我們成功執行第一個測試案例,從 Python 腳本透過 Appium 控制模擬器點選設定中的電池,下個問題就是怎麼找元件,這時候就要請出 Appium Inspector 了
前言 經過五個小單元的準備,終於可以開始跑第一個測試了,Appium 本身是個工具,可以搭配各種語言,這邊選擇 Python 作為測試腳本語言,以便之後跟 Robot Framework 串接。