選單

自動化測試中的臨時信箱 API:建立、輪詢、驗證

在自動化測試裡使用臨時信箱 API:透過 HTTP 建立收件匣、輪詢確認信、擷取驗證碼,並在 CI 中完成清理。

發佈於

  • 自動化
  • 測試信箱
  • 持續整合

確認信是註冊流程裡瀏覽器測試自己走不完的一環。總得有個東西持有地址、收下信件、把驗證碼交回給測試。臨時信箱 API 做的就是這件事:測試套件透過 HTTP 向服務申請一個收件匣,讀取到達的信件,用例結束後丟棄它。沒有瀏覽器,沒有多人共用的信箱,也不需要手動複製貼上。

本文談的是這套機制裡 API 的那一側。它不是把被測應用指向本機收信連接埠——那是在持續整合裡擷取郵件的做法,兩者解決的是不同問題。本機擷取證明的是你的應用送出了什麼;臨時信箱 API 證明的是信件經過真實投遞鏈路、真的到達了一個由測試持有的地址。

為什麼要在測試裡用信箱 API?

因為另一個選擇不是真人信箱,就是什麼都沒有。

共用信箱是很糟的測試夾具。多個執行讀同一個信箱,上一輪的信還留在裡面,地址還會累積沒人要的流量。於是每條斷言都得猜哪封信屬於當前用例,而猜測正是偶發失敗的來源。

用瀏覽器去抓服務商網頁是第二個壞選擇。它讓測試依賴隨時會變的版面結構、依賴工作階段狀態,還要看管一個登入。服務商一改按鈕樣式,綠色套件就會因為與產品無關的原因變紅。

信箱 API 同時去掉這兩個問題。地址是為用例建立的,天生是空的,讀取走的是測試能直接呼叫的穩定介面。套件不再在意服務商長什麼樣,只在意契約成立:建立、接收、讀取、刪除。

還有一個隱私層面的理由。透過介面建立的地址不代表任何人。它不是某個人的信箱,真實信件不會落到那裡,而且它隨這次執行一起被丟棄。

測試真正需要哪些端點?

信箱 API 可以暴露幾十條路由,但測試客戶端只需要四類操作,而且最好依照套件使用它們的方式來命名。

建立會回傳一個地址和一個控制代碼。地址是要告訴被測應用去寄送的目標;控制代碼通常是權杖或識別碼,測試在後續每次呼叫裡用它來詢問這個收件匣。套件應該把兩者當成一個物件,絕不要從地址反推控制代碼,因為服務商完全可以讓兩者毫無關係。

列表回傳摘要而不是內文:每封信一筆,帶識別碼、寄件人、主旨和到達時間。這是輪詢迴圈應該用的呼叫,因為它便宜,而且足以回答早期唯一重要的問題——有沒有東西到達。

讀取回傳一封完整信件,包含純文字和 HTML 兩部分。驗證碼就在這裡,這個呼叫應該只在列表回報命中之後才發出。

清空會把收件匣裡的信刪掉,或者整箱刪除。測試需要它有三個原因:在多次嘗試之間重置而不新建地址、在用例結束時清理,以及讓收件匣回到可預期的狀態。

有些服務還提供等待或長輪詢端點,在訊息到達或逾時前一直掛著連線。它很方便,但客戶端仍應能退回列表,因為等待呼叫最容易被限流。

如何輪詢驗證碼而不引入偶發失敗?

這類測試裡最常見的錯誤是固定睡眠。寫死幾秒是猜:投遞慢時太短,投遞快時又白等,在負載高的 CI 機器上兩個方向都可能出錯。把它換成一個迴圈:呼叫列表、檢查是否命中、一旦找到就回傳,並設一個上限,逾時就判失敗而不是把工作掛死。

比對是問題的另一半。測試要的那封信,是寄給當前用例所建立地址的那封;如果收件匣裡可能有許多種信,還要選主旨裡帶穩定片段的那封。命中多封時取最新的,這樣重試帶來的重複投遞不會干擾讀取。絕不要無條件取第一封——在重複使用地址的情況下,這正是把舊驗證碼當成新驗證碼來驗證的方式。

擷取要有錨點。內文裡可能有參考號、時間戳和價格,一個抓取第一串數字的解析器有時會抓錯。先找到引出驗證碼的措辭,再從它附近讀取驗證碼,比對不到時就把原內文一起報出來。

最後,尊重重送限制。驗證碼流程通常只允許在短時間視窗內寄幾次,這個限制本身就是被測行為的一部分。測試為了拿到新驗證碼再去按一次按鈕,最終會被拒絕,然後因為錯誤的原因失敗。重試應該是再讀一次信箱,而不是再觸發一封信。

如何接入端到端或 CI 套件?

乾淨的做法是一個夾具。流程開始前,夾具建立一個收件匣並回傳地址;測試用這個地址驅動應用;應用確認已經送出之後,斷言讀取信箱並擷取驗證碼;用例結束時,夾具刪除收件匣。

客戶端要小、要可注入。用一個模組包住這四類呼叫,測試只依賴這個模組,而不是讓原始 HTTP 散落在套件各處。這樣既能給單元測試換成假實作,也能把同一套件指向別的服務商而不重寫斷言。

在 CI 裡,憑證放在工作的密鑰儲存中,絕不進倉庫,也絕不進日誌。給每個工作或每個並行 worker 自己的收件匣,並在產生的地址上加能標識本次執行的前綴,這樣一封走失的信可以靠觀察來歸屬。把客戶端逾時設得比工作本身的逾時更短,卡住的輪詢就會給出清楚訊息,而不是讓工作被突然取消。

重試讀取,而不是重跑整個流程。驗證碼還沒到時,等一等再讀;重跑註冊會再產生一封信,也就給斷言多出一個候選項。另外,別把信箱 API 用進生產流程:它是測試基礎設施,套件永遠不應該透過它給真實客戶寄信。

圍繞驗證碼的流程本身,而不是讀取機制,見信箱驗證流程怎麼測;解析這一步單獨展開在端到端測試裡的 OTP。

隔離與清理

每個用例一個地址,是避免大多數跨用例失敗的原則。它省去了判斷哪封信歸誰的推理,也讓新鮮度問題消失,因為這個收件匣從頭到尾只收到過一個用例的流量。

清理要顯式且無條件。在無論用例通過還是失敗都會執行的收尾裡刪除收件匣,而不是只在成功路徑上做。只依賴服務商的存活時間是個錯誤:信件可能留得夠久,久到被同一台機器上稍後的執行讀到;那個存活時間只是便利,不是保證。

如果清理失敗,記下來然後讓套件跑完。清理錯誤值得知道,但它不等於產品缺陷;因為清理失敗就判整輪失敗,會教會團隊忽略收尾階段的報錯。地址收到的一切都當測試資料處理:它只為一條斷言存在,不應被匯出或分享,也絕不能被當成任何人的聯絡方式。

限制與注意事項

信箱 API 仍然是第三方相依,它的限制就是你測試的限制。每分鐘限流可能拒絕大規模並行執行帶來的批次建立;配額會限制同時存在的地址數量;信件可能延遲,而延遲的信件在到達前看起來和遺失一模一樣。

臨時網域也普遍被封。服務商的網域可能被你在測的那個註冊表單拒收,讓一個本來正常的測試變成看不懂的失敗。遇到這種情況,答案不是給服務商開特例,而是先弄清被測產品是不是有意拒絕臨時地址,然後刻意地把這個行為測出來。

誠實的總結是:信箱 API 適合斷言到達了什麼;要斷言你的應用送出了什麼,本機收信端更快,也沒有配額。成熟套件通常兩者都用:大部分斷言走本機擷取,只有在真實投遞鏈路本身是被測對象時才用信箱 API。

下一步

找出一個輪詢共用信箱、專門讀驗證碼的測試,把它換成一個從信箱 API 建立新地址的夾具。把地址隨執行一起寫進日誌,在收尾裡刪掉它,然後看看你原本容忍的偶發失敗有多少直接消失了。需要人工收一封真實信件時,臨時信箱片刻就能建立一個地址;它發出去的地址只是某次執行的鷹架,從來不是真實身分。

繼續閱讀

臨時信箱(一次性信箱/10 分鐘信箱)相關文章