iT邦幫忙

2026 iThome 鐵人賽

DAY 15
0
Software Development

同一套 Laravel 系統,測試怎麼寫才不會說謊系列 第 15

Day 15:附件測試——同一支 class 要吃三種舊系統資料格式,怎麼用 dataset 一次測完

  • 分享至 

  • xImage
  •  

前言

「同一段解析邏輯要處理好幾種輸入格式,測試該怎麼寫才不會變成複製貼上三份幾乎一樣的程式碼?」

這個系統有一個很典型的場景:外部系統回傳的新聞附件資訊,可能是 XML 格式,也可能是陣列格式,這兩種格式還各自有不同的變形。負責解析的類別要把這些格式全部統一轉換成同一種標準結構。今天要講的是這段邏輯的測試怎麼寫——答案是用 Pest 的 dataset 語法,一次把多種輸入變形都測到,不用手動複製貼上。

今日目標

  • 認識一個「同一支類別要吃多種舊格式資料」的真實場景
  • 學會用 Pest dataset 語法一次測完多種輸入變形
  • 理解 dataset 測試設計的核心:測試邏輯只寫一次,測試資料各自獨立
  • 建立判斷力:什麼時候該用 dataset,什麼時候該拆成獨立測試

一段要吃多種格式的解析邏輯

外部系統傳回的新聞附件資訊,格式並不統一——有時候是 XML 節點(SimpleXMLElement),有時候是已經轉換成陣列的資料,而且陣列格式裡欄位的命名方式在不同時期還不太一樣。負責解析這段資料的類別,要把這些輸入統一轉換成同一種標準結構(例如固定包含網址跟替代文字兩個欄位),提供給前台畫面統一使用。

如果每種格式各寫一支獨立的測試,會出現三、四支結構幾乎一模一樣的測試檔案——建立輸入資料、呼叫同一個解析方法、斷言輸出結構一致,唯一的差異只有輸入資料的格式。這種情況正是 dataset 測試語法要解決的問題。

兩種寫法的對照

每種格式各寫一支重複的測試

test('parses xml format', function () {
    $xml = new SimpleXMLElement('<attachment><url>x.jpg</url></attachment>');
    $result = NewsAttachment::parse($xml);
    expect($result)->toBe(['url' => 'x.jpg', 'alt' => '']);
});

test('parses array format', function () {
    $array = ['url' => 'y.jpg', 'description' => 'desc'];
    $result = NewsAttachment::parse($array);
    expect($result)->toBe(['url' => 'y.jpg', 'alt' => 'desc']);
});

// 還有第三種、第四種格式,各自再複製貼上一次

每支測試的骨架完全一樣,只有輸入資料跟預期輸出不同——複製貼上三、四次之後,如果哪天解析邏輯本身要調整(例如換一種斷言方式),要同步改三、四支測試,很容易漏改。

用 dataset 把測試邏輯跟測試資料分開

test('parses attachment from various legacy formats', function (mixed $input, array $expected) {
    expect(NewsAttachment::parse($input))->toBe($expected);
})->with([
    'xml format' => [
        new SimpleXMLElement('<attachment><url>x.jpg</url></attachment>'),
        ['url' => 'x.jpg', 'alt' => ''],
    ],
    'array format with description' => [
        ['url' => 'y.jpg', 'description' => 'desc'],
        ['url' => 'y.jpg', 'alt' => 'desc'],
    ],
    // 再加一種新格式,只要加一筆 dataset,不用再寫一次測試邏輯
]);

測試邏輯只寫一次,每一種輸入格式變成 ->with([...]) 裡的一筆具名資料。之後如果外部系統又冒出第五種格式變形,只要在陣列裡加一筆,不用複製貼上整套測試骨架;如果解析邏輯本身要調整斷言方式,也只要改一個地方。

dataset 不是萬用解法

不是所有多輸入情境都適合塞進同一個 dataset。如果不同輸入格式除了資料形狀不同之外,還需要不同的前置設定(例如某種格式需要先 mock 一個完全不同的服務),硬塞進同一個 dataset 反而會讓測試函式裡塞滿條件判斷,變得比拆成獨立測試更難讀。dataset 適合的場景是:測試邏輯完全相同,只有輸入資料跟預期輸出不同——這個附件解析的案例剛好符合這個條件,才值得用 dataset 收斂。

今日思考題

回想你手上專案裡,有沒有幾支測試檔案長得幾乎一模一樣,只是輸入資料不同?如果把它們改寫成 dataset,測試邏輯本身會不會變得更容易一眼看懂測的是同一件事的不同變形?

今日重點回顧

  • 一段要處理多種舊系統資料格式的解析邏輯,適合用 Pest dataset 語法測試
  • dataset 把「測試邏輯」跟「測試資料」分開,邏輯只寫一次,資料各自獨立列出
  • 新增一種輸入格式時,只需要加一筆 dataset,不用複製貼上整套測試骨架
  • dataset 適合「測試邏輯完全相同、只有輸入輸出不同」的場景,不是所有多輸入情境都適合

明日預告

明天要拆解兩支自製的測試替身——同一份錄影帶,怎麼讓兩支負責不同通訊協定的 Fake 各自挑自己看得懂的部分播放。


上一篇
Day 14:一支被 skip() 掉的登入測試——測試覆蓋率數字 vs 實際保護力落差
下一篇
Day 16:Fake 測試替身設計——同一份錄影帶,兩支不同協定的 Fake 各自挑自己看得懂的部分播放
系列文
同一套 Laravel 系統,測試怎麼寫才不會說謊16
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言