iT邦幫忙

2024 iThome 鐵人賽

DAY 22
0
Software Development

全端實戰心法:小團隊的產品開發大小事系列 第 22

整合測試:確保基本功能不會被改壞

  • 分享至 

  • xImage
  •  

前幾講我們聊到測試金字塔底端的 Unit Testing,這是撰寫和測試時間成本最低的一種測試,但是針對的是範圍最小的 Function,而一個實際的功能卻是由若干小 Functions 所組成的。

就算每個小 Functions 都通過單元測試,也並不代表這個功能就沒有問題,如果要確保功能的正確性,我們還需要把他們綑起來一起測試,這便是我們今天要談的內容:位於測試金字塔中間的整合測試(Integration Testing)。

什麼是整合測試?

只要是將多個 Functions、Components 兜起來一併測試,廣義上來說,都能稱作整合測試(Integration Testing)。

但是在我自己狹義的定義中,每個整合測試的範圍,都需要滿足一個「功能」,這裡的功能指的是和客戶或 Product Owner 談完需求後,所其衍伸出的功能。

例如我們要滿足一個商品管理的需求,其中的「新增商品」就是此需求中的一個子功能。這個子功能可能會包含許多個 Modules,例如有商品名稱檢查的 Validation Function,也有連結到某個既有商品類別的 Function 等等。

這些 Modules 打包起來,整合在新增商品這個子功能底下一起測試,就是一個整合測試的測項了。

對我來說,做整合測試的目的是將絕大部分需求所衍伸出來的功能測完,藉此保證需求變更時,改程式碼不會把既有的功能給改壞。

整合測試:API Testing

其中我最常做的就是單測後端提供給前端的 API Testing 了,因為每個 API 都是因為開了需求而最終實作出來的,如果我們能確保 API 的 Interface 和行為都是正確的,就能很大程度的保證就算包含前端,也不會讓整個產品有太大問題。

那麼,為何不把前端也納入做整合測試呢?原因是成本考量。

首先我們得等 API 完成後,前端也串完 API 了才能夠測試,在開發時間上會需要延遲一些;再者 API 的許多參數數入,會依賴前端的不同 UI Component 來輸入,例如商品的名稱、數量、類別可能要分別用到 Input Box、Dropdown Menu 等等的操作,我們可能需要先模擬一個瀏覽器操控 HTML 的 DOM 來和這些元件互動。

雖然從前端,一路到後端、資料庫這種稱作 End-to-End 的測試我們也有必要做,但是其成本比較高,所以在考慮時間因素後,可以挑幾個有代表性的做就好了。

API Testing,模擬前端會送出的 Request
*API Testing,模擬前端會送出的 Request

回到 API Testing,如果我們寫一支程式來送 Request 給後端,屏蔽掉前端需要操縱 DOM 的 Effort,就能把大部分 API Parameters 的排列組合測一遍,做整合的 Boundary Tests。

整合測試的環境架設,以及被允許的 Side Effect

而另一個問題是,我們有需要把資料庫也啟動來測試嗎?

在 Unit Testing 當中,因為希望程式的依賴少一些,跑的速度快一些,我們使用 Stub 及 Mock 這兩招來隔絕依賴,所以並不會真的跑一個資料庫來測試。

然而我一般在 Integration Testing 當中,則會真的啟動一台資料庫,讓我們要測試的功能能盡量符合真實的情境。並且,我會利用資料庫這個後端的外部環境,造成不同測項之間有 Side Effect。

這樣做有什麼好處嗎?每個測試不是都該保持獨立性,跑完之後不影響到其他測項,來避免每次執行測試的結果都一致嗎?

如果這個些測項本身都是互有依賴的,我們其實就可以將他們當成同一組 Test Suite 來測試,因為有些測項的先決條件其實是另一個測項,我們只要確保兩組不同的 Test Suites 之間是相互獨立的即可。

整合測試範例:商品 CRUD

我們來看看一組簡單的範例,商品 CRUD(Create, Read, Update, Delete)。我們新增完畢之後,需要讀取才能確認結果,這兩個功能就是相互依賴的;相對的,更新和刪除之後也都需要讀取才能確認結果,所以這四種操作屬於同一個 Test Suite 就是很合理的事情。

進一步來說,如果讀取的功能壞掉了,就算新刪修這三個功能正常運行,整個服務在商品管理這塊也等同是失效的,因為連商品都讀不到,就算能新增又有何意義。

那麼我們接著看,這樣一組 Test Suite 具體的步驟會是如何的:

首先為了確保每一組 Test Suite 是互相獨立的,我們在 Test Suite 的一開始會把資料庫的內容清掉,並重新啟動 Server,讓整個環境的初始狀態是乾淨的,如果這組測試有一些先決條件,例如需要使用者登入的話,我們就會在稱作 Setup 的步驟去取得登入所需的 Token。

如果想要讓測試的速度加快,不要每次都重啟伺服器和刪除資料庫的資料,也可以加入 Tear Down 這個步驟把污染了此環境的資料刪除,但是需要注意刪除也是有可能失敗的,如果發生這種狀況的話可能就會影響到接下來的測試,因此整個環境重啟會是最乾淨的方法。

商品 CRUD 測試範例
*商品 CRUD 測試範例

再來則是實際的測項,新增商品時會傳入參數,例如 { name: '蘋果' },Server 的回傳值有些會實作成新增成功的商品也回傳,有些則只會通知成功與否。

下一個步驟就是讀取的 Request 了,這個測項依賴上一個新增測項的結果,所以我們期望讀取出來的商品列表,包含剛剛的 { name: '蘋果' } 物件,並且還有一個 ID。

最後則是重複類似的行為來測試更新和刪除這兩個操作,同樣都可以透過讀取來確認兩個動作是否成功,但需要注意的是,同一個 Test Suite 中的測項如果有相依性的話,記得要按照順序執行,有些測試框架會預設平行的執行每個測項,就有可能會造成失敗。

通過這樣 API 整合測試,就能在功能的實作上降低出錯的可能性了!


上一篇
單元測試(三):前端有哪些重點 Unit Tests 要寫?
下一篇
端到端測試:交付前的最終測試
系列文
全端實戰心法:小團隊的產品開發大小事30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言