在雲端原生時代,無伺服器應用程式日益普及,其彈性與可擴充套件性深受開發者青睞。然而,由於其分散式架構和高度依賴雲端服務,測試無伺服器應用程式也面臨獨特挑戰。本文將深入探討如何有效測試無伺服器應用程式,特別關注商業邏輯、整合點與資料契約的測試,並提供整合測試檢查清單,協助開發者建構更穩健的無伺服器應用程式。同時,我們也將探討如何透過單元測試、整合測試和端對端測試的組合,確保程式碼品質和系統穩定性,最終交付符合使用者需求的高品質產品。

定義「完成」

軟體工程應該是一種社會活動,使用者的需求應該被放在最高的地位。但是,最好的軟體是正在被使用的軟體。如果你不釋出你的軟體,你永遠不知道它是否真的能夠在生產環境中正常運作,面對真實的流量和變數。一個「完成」清單可以給你信心去釋出:不是因為你的改變是否會工作,而是因為你會知道如果它不工作。

如何決定是否可以釋出變更?

回答以下問題可以幫助你實際地決定是否可以釋出變更:

  1. 如何衡量這段程式碼的品質?
  2. 這段程式碼如何釋出到生產環境?
  3. 如何知道這段程式碼是否在生產環境中壞了?
  4. 如何知道這段程式碼是否在釋出前壞了?
  5. 如果這段程式碼在生產環境中壞了,如何除錯?
  6. 如何從生產環境中的失敗中還原?

無伺服器應用程式測試

無伺服器應用程式通常由管理服務、事件驅動互動和商業邏輯組成。有效的測試需要明確界定你和 AWS 之間的責任。你需要測試你所擁有的商業邏輯和整合組態。

事件驅動測試

事件驅動無伺服器應用程式由商業邏輯、管理服務和整合點組成。你需要測試商業邏輯、整合點和資料契約。

商業邏輯

商業邏輯是你編寫和佈署到 AWS 的程式碼,代表著應用程式的功能需求和商業規則。你需要測試這部分的程式碼。

整合點

整合點是分散式元件之間的通訊方法和訊息格式。你需要組態整合點和定義通訊規則。

資料契約

資料契約是一套編碼規則,促進邏輯解耦服務之間的通訊。這些契約在整合點上強制執行,確保可驗證的通訊和可擴充套件的測試策略。

測試策略

根據以上元素,你可以制定一個測試策略,包括:

  1. 單元測試:測試商業邏輯和整合點。
  2. 整合測試:測試整合點和資料契約。
  3. 端對端測試:測試整個應用程式流程。

透過這種方式,你可以確保你的無伺服器應用程式是可靠和高效的,並且能夠滿足使用者的需求。

整合測試檢查清單

在進行整合測試時,需要針對每個整合點捕捉失敗模式,並決定是否需要撰寫測試來涵蓋這些失敗模式。以下是整合測試檢查清單:

失敗類別

  • 組態:您負責組態受管理服務之間的整合點,例如事件匯流排和規則。您應該驗證整合是否存在且按照AWS規則和您的商業需求進行組態。建議使用基礎設施測試和單元測試。
  • 許可權:您負責授予必要的許可權,以便整合元件之間可以相互互動。您應該驗證來源元件是否具有發布事件或訊息的許可權,目標元件是否具有消費事件或訊息的許可權。建議使用基礎設施測試。
  • Payloads:通訊通道和訊息payload使用玄貓進行通訊。建議使用單元測試、契約測試和靜態分析。

測試原則

  • 不要在測試中耦合已經解耦的元件。
  • 盡可能地單獨測試整合點的來源和目標。
  • 單元測試業務邏輯在Lambda函式中。

單元測試業務邏輯

業務邏輯是寫在Lambda函式中並由其執行的。因此,大部分業務邏輯測試可以透過斷言Lambda函式各種操作的單元測試來實作。您通常會單獨測試Lambda函式的個別操作,而不是測試整個函式。

使您的Lambda函式可測試通常涉及抽象和隔離您的業務邏輯,並與測試檔案分享方法。以下是Node.js Lambda函式的簡單示例:

export const greeting = (name) => {
  return `hello ${name}`;
}

export const handler = async (event) => {
  return greeting(event.name)
};

相應的單元測試可以匯入抽象方法並在隔離中驗證它:

import { greeting } from "./";
test("Should say hello world", () => {
  const actual = greeting("world");
  const expected = "hello world";
  expect(actual).toEqual(expected);
});

Mocking

單元測試應該是可預測的。換句話說,單元測試應該在每次執行時產生相同的結果,假設輸入相同。以下是addNumbers方法的示例:

export const addNumbers = (a, b) => {
  return a + b;
}

對於這個方法,您可以撰寫一個單元測試來驗證其行為:

import { addNumbers } from "./";
test("Should add two numbers", () => {
  const actual = addNumbers(2, 3);
  const expected = 5;
  expect(actual).toEqual(expected);
});

在這個例子中,addNumbers方法是可預測的,因為它每次都會傳回相同的結果,假設輸入相同。這使得撰寫可靠的單元測試變得更加容易。

從技術架構視角來看,建構可靠的無伺服器應用程式需要一套嚴謹的測試策略。本文深入探討瞭如何定義「完成」,並闡述了從程式碼品質衡量到生產環境除錯的完整流程。尤其針對無伺服器應用程式的特性,文章提出了根據事件驅動、商業邏輯、整合點和資料契約的多層次測試方法。單元測試、整合測試和端對端測試的組合,確保了應用程式各個環節的穩固性。文章更進一步提供了整合測試檢查清單,涵蓋組態、許可權和 Payloads 等關鍵導向,並輔以實務程式碼範例,展現瞭如何有效地進行單元測試和 Mocking。然而,目前測試策略的自動化程度及與 CI/CD 流程的整合仍是待最佳化的方向。展望未來,隨著無伺服器技術的持續發展,更精細化、自動化的測試工具和框架將成為提升開發效率和應用程式品質的關鍵。玄貓認為,開發團隊應積極探索新的測試方法,並將安全性和效能測試納入考量,才能在快速迭代的開發週期中,確保無伺服器應用程式的穩定性和可靠性,最終交付高品質的產品。