前言:API 測試工具的痛點與 2026 年的轉折點
API 測試工具大概是後端工程師每天一開機就會打開的東西。這幾年我自己跟團隊都是用 Postman,介面直覺、上手快,一度是業界的標準配備。但用久了會發現它慢慢變重,而且 2026 年的這波改版讓不少團隊踩到痛點——免費方案被限縮成只能單人使用,想要團隊協作就得升級到每人每月 1,140 美元的授權費,對新創或中小團隊來說,其實不算小數目。
我也試過幾個替代方案。VS Code 的 REST Client 擴充很輕量,但少了獨立 GUI 跟集合管理,專案一大就不太好維護;另一個老牌開源專案 Hoppscotch(以前叫 Postwoman)也不錯,不過它偏 Web-based,在離線使用跟企業敏感資料的隱私上,我們資安的同事多少還是有點疑慮。
我在回顧改善開發者體驗,我做了些什麼?裡聊過,工具鏈跟開發流程的優化,往往是團隊效率能不能拉起來的關鍵。後來我把目標放到一款叫 Bruno 的開源 API 測試工具上——它在 GitHub 上已經超過 50,000 顆星、用的是寬鬆的 MIT 授權,最吸引我的是它兩個設計理念:Git 原生跟完全離線。而 Git 原生這件事,後面會講到,剛好讓它在這個 AI 協作的年代特別吃香。
為什麼選擇 Bruno?核心優勢與技術架構
Bruno 跟傳統 API 測試工具最大的差別,在於它「怎麼存資料」這件事的思考。
1. 檔案系統優先(File-System First)
Postman 的資料預設同步到雲端,不然就是匯出成一大坨很難做版本控制的 JSON。Bruno 反過來走檔案系統優先的路線:每一個 API 請求都是一個獨立的純文字 .bru 檔(用它自家的 Bru Markup Language 寫的)。
這代表你可以把 API 測試檔直接放進專案目錄,跟著程式碼一起 commit 進 Git,也能透過 Pull Request(PR)做 code review。下面是一個典型的 .bru 檔長什麼樣子:
meta {
name: 取得會員資料
type: http
seq: 1
}
get {
url: {{baseUrl}}/api/v1/users/123
body: none
auth: bearer
}
auth:bearer {
token: {{token}}
}
assert {
res.status: eq 200
res.body.status: eq "success"
}
2. 完全離線,資料留在自己手上
Bruno 預設 100% 離線跑,不會強迫你綁雲端帳號。所有的 API 集合、環境變數、機密資訊都只留在你本機硬碟裡。對在意資安跟資料隱私的公司來說,這等於從根本上避免了敏感 API 資訊被同步到第三方雲端的風險。
3. 功能不陽春,還能接 CI/CD
別看它輕量,Bruno 功能其實很完整——REST、GraphQL、WebSocket 都支援,也能用 JavaScript 寫 Pre-request 腳本跟 Post-response 斷言(Assertions)。再配上官方的 @usebruno/cli,要把 API 測試塞進部署流程、做自動化迴歸測試也不難。
4. Git 原生,剛好超好跟 AI 協作
這點是我後來最有感、但一開始沒料到的好處。
因為 .bru 就是純文字、又跟程式碼一起放在 Git 倉庫裡,現在的 AI 工具(GitHub Copilot、Cursor、Claude Code 這類)可以直接讀、直接寫這些測試檔。實際用起來會變成這樣:
- 叫 AI 幫你補測試:我寫完一支新的 API,直接跟 Claude Code 說「照這支 controller 幫我生一份 Bruno 測試,成功跟幾個錯誤情境的斷言都補上」,它就能生出對應的
.bru檔丟進tests/api/,不用我一個欄位一個欄位手點。 - PR 裡看得懂的 diff:因為是純文字,AI 在 review PR 時看得懂這次新增、改了哪些 API、斷言動了什麼。換成 Postman 那種雲端集合或巨大 JSON,不管是 AI 還是人都很難 diff。
- 規格、程式、測試在同一個 repo:AI agent 最吃「上下文」。當 API 的程式碼、
.bru測試、甚至 spec 文件都在同一個 git repo 裡,AI 一次就能拿到完整脈絡,生出來的東西命中率高很多。
簡單講:Postman 那種「測試躺在另一個雲端 App 裡」的模式,AI 根本搆不到;Bruno 把測試變成 repo 裡的純文字檔,等於順手把 API 測試也納進了 AI 協作的範圍。這也是我會建議現在就換過來的最大理由。
為了讓大家更直觀地看出差異,我整理了下面這張比較表:
| 功能 / 特性 | Bruno | Postman (2026 方案) | VS Code REST Client |
|---|---|---|---|
| 授權模式 | 開源 (MIT) | 閉源商用 (限制免費) | 開源 |
| 團隊協作費用 | $0 (開源版) | $19 / 使用者 / 月 | $0 |
| 儲存方式 | 本地純文字 (.bru) | 雲端同步 / 巨大 JSON | 本地純文字 (.http) |
| Git 友善度 | 非常高 (PR 衝突極易解決) | 差 (衝突時難以合併) | 高 |
| AI 協作友善度 | 非常高 (純文字,AI 可直接讀寫 / review) | 低 (雲端集合,AI 搆不到) | 高 (純文字 .http) |
| GUI 介面 | 獨立桌面應用程式 | 獨立桌面應用程式 | 整合於 VS Code 內 |
| CLI 執行 | 支援 (@usebruno/cli) | 支援 (Newman) | 支援度較受限 |
實作步驟:從安裝到團隊協作工作流
接下來我直接示範怎麼把 Bruno 帶進日常的開發工作流。
步驟一:跨平台安裝與建立 Collection
Bruno 跨平台支援 Windows、macOS 與 Linux。可以直接上官網下載,或用套件管理器快速安裝:
# macOS (Homebrew)
brew install bruno
# Windows (Chocolatey)
choco install bruno
裝好之後打開 Bruno,選 "Create Collection"。我的習慣是把這個 Collection 的目錄直接指到正在開發的專案資料夾裡(例如 ./tests/api),這樣 API 測試檔就能跟專案程式碼放在一起管理。
步驟二:配置環境變數與 API 請求
實際開發通常會分開發(Dev)、測試(Test)與生產(Production)幾個環境。在 Bruno 點右上角的環境設定圖示,就能建立不同的 Environment。
舉例來說,建一個 Dev 環境、加一個 baseUrl 變數;之後設定 API 請求時,只要用雙花括號 {{baseUrl}} 就能動態帶入。
💡 實戰小技巧:如果你的專案有部署 API 網關來管理流量,可以參考打造高效 API 管理平台:從 0 開始部署 Kong Gateway - Part 1 來搭建後端基礎設施,再透過 Bruno 做端對端的介接測試。
步驟三:編寫測試斷言與腳本
Bruno 裡可以用 JavaScript 處理比較複雜的 API 流程。比方說發送前要動態算一組簽章,或是收到回應後把 Token 自動寫進環境變數。
在 Script 頁籤的 Post-Response 可以這樣寫:
// 取得回應中的 Token 並寫入環境變數
const data = res.getBody();
if (data && data.token) {
bru.setEnvVar("token", data.token);
}
Pre-request 腳本在串接金流時的實戰用法
Pre-request(發送前)腳本這格,我最常拿來對付金流串接。台灣常見的金流(綠界 ECPay、藍新 NewebPay、Stripe 這類)幾乎都要在送出前先算一組檢查碼/簽章,用來驗證這次請求沒被竄改。這種簽章的規則通常是「把參數照字母排序 → 前後夾上商店金鑰 → URL encode → 轉小寫 → 做 SHA256/MD5 → 轉大寫」,每次參數一變,簽章就得重算。手動算根本不可能,正好交給 Pre-request 腳本在送出前自動生成。
以綠界 ECPay 的 CheckMacValue 為例,在 Script 頁籤的 Pre Request 可以這樣寫:
const CryptoJS = require("crypto-js");
// 這次交易要送的參數(實務上可從環境變數帶入)
const params = {
MerchantID: bru.getEnvVar("merchantId"),
MerchantTradeNo: "TEST" + new Date().getTime(),
TotalAmount: "1000",
TradeDesc: "Bruno 測試訂單",
ItemName: "測試商品",
ReturnURL: bru.getEnvVar("baseUrl") + "/api/payment/callback",
};
const hashKey = bru.getEnvVar("ecpayHashKey");
const hashIV = bru.getEnvVar("ecpayHashIV");
// 1. 參數依 key 字母排序後組成 query string
const sorted = Object.keys(params)
.sort()
.map((k) => `${k}=${params[k]}`)
.join("&");
// 2. 前後夾上 HashKey / HashIV
let raw = `HashKey=${hashKey}&${sorted}&HashIV=${hashIV}`;
// 3. URL encode 後轉小寫(綠界指定的 .NET UrlEncode 規則)
raw = encodeURIComponent(raw)
.toLowerCase()
.replace(/%20/g, "+")
.replace(/'/g, "%27")
.replace(/~/g, "%7e")
.replace(/%21/g, "!")
.replace(/%2a/g, "*")
.replace(/%28/g, "(")
.replace(/%29/g, ")");
// 4. SHA256 後轉大寫,即為 CheckMacValue
const checkMac = CryptoJS.SHA256(raw).toString().toUpperCase();
// 5. 把算好的參數與檢查碼塞回環境變數,供請求 body 使用
Object.keys(params).forEach((k) => bru.setEnvVar(k, params[k]));
bru.setEnvVar("CheckMacValue", checkMac);
接著在請求的 body 裡直接用 {{MerchantTradeNo}}、{{CheckMacValue}} 這些變數帶入即可。這樣設計的好處是:簽章邏輯集中在 Pre-request 一處,每次發送都會用最新的參數即時重算,不用擔心改了金額卻忘記重簽而被金流閘道退件。藍新 NewebPay 的 AES 加密、Stripe 的 Idempotency-Key 也是同樣的套路——凡是「送出前要根據參數動態產生某個欄位」的情境,都適合放在 Pre-request 腳本裡處理。
💡 小提醒:金流的
HashKey、HashIV、MerchantID這類機密千萬別寫死在.bru檔裡跟著 commit 進 Git。把它們放進 Bruno 的環境變數(甚至用.env搭配{{process.env.XXX}}),才不會讓商店金鑰外洩到版控。
斷言的部分,Assert 頁籤可以直接用宣告式的方式設定預期結果,不用寫一堆 JS:
| Expression | Operator | Value |
|---|---|---|
res.status | eq | 200 |
res.body.data.id | isDefined |
步驟四:CI/CD 與 Git 協作
在 Bruno 裡新增或改了 API 請求後,你會看到專案目錄的 tests/api 多了對應的 .bru 檔。直接 commit 並 push 上去:
git add tests/api/
git commit -m "feat: 新增使用者 API 與相關測試案例"
git push
CI/CD 這邊就用官方 CLI 來自動跑這些測試。下面是一個 GitHub Actions 的工作流(Workflow)範例:
name: API Regression Testing
on: [push, pull_request]
jobs:
api-test:
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install Bruno CLI
run: npm install -g @usebruno/cli
- name: Run API Tests
run: bru run tests/api --env Dev
這樣一來,團隊每次開 PR,系統都會自動跑一次 API 測試,確保沒有哪個現有介面被改壞。
💡 延伸閱讀:除了 API 層級的合約測試,如果你也需要針對前端介面或核心商業網站做端對端的完整情境驗證,可以參考用微軟 playwright 輕易搭建 End to End Testing 自動化測試環境,保護公司的核心商業網站,並整合 Teams 通知及外部觸發,兩者搭配能建立更穩固的測試防護網。
注意事項:轉移時的限制與坑
Bruno 的好處很明顯,不過從 Postman 搬過來的過程,我也踩到幾個要先有心理準備的地方:
- 腳本遷移成本:Bruno 雖然支援 JavaScript,但它內建的 API 物件跟 Postman 的
pm.*(像pm.test、pm.expect)並不完全相容。如果你的 Postman 集合裡塞了一堆複雜的前置/後置腳本,匯進 Bruno 後得花點時間手動改寫。好消息是這種機械式的改寫,現在丟給 AI 處理很快——這又繞回前面講的,純文字 + AI 協作的好處。 - 付費牆界線:Bruno 的核心功能(CLI、環境變數、腳本這些)完全開源免費,但它也有一個 Ultimate Edition(年訂閱制)的付費版,主要是一些企業級的進階功能(內建 LDAP 整合、更細的 UI 自訂等)。評估的時候建議先用開源版,以我自己的經驗,大概 95% 以上的日常需求都已經夠用了。
結論:導入後的收益與下一步
換成 Bruno 之後,我最有感的收益是程式碼跟 API 測試/文件不再各自分家。現在 API 一有變動,對應的測試會跟著功能程式碼在同一個 PR 裡被 review、被跑過,再也不會出現「程式碼都改了,但測試工具裡的 Collection 還停在舊版本」這種尷尬狀況。順帶一提,團隊也徹底擺脫了 Postman 逐人計費的授權壓力。
但對我來說,真正讓我覺得「現在就該換」的,是它跟 AI 協作的契合度。當 API 測試變成 repo 裡的純文字檔,它就跟程式碼一樣,能被 Copilot、Claude Code 這些工具直接讀、直接寫、直接在 PR 裡 review。在這個越來越多事情交給 AI 代勞的年代,把工具選成「AI 搆得到」的形態,本身就是一種生產力。
如果你的團隊現在也卡在 API 工具的收費問題,或單純想讓 API 測試更貼近 Git 工作流,我會建議先挑一個現有專案的單一微服務試水溫:把 API 集合建在專案裡,實際跑一次「用 Git PR 協作 API」,再順手叫 AI 幫你補幾份測試,應該很快就能感覺到差別。
參考資料
- Bruno 官方網站
- GitHub - usebruno/bruno
- Bruno vs Postman 官方比較指南
- REST API Testing in 2026: Bruno, Hoppscotch, and Moving on from Postman























留言