2024-10-24 014_學寫API_如何撰寫 API 的單元測試

2024-10-24 014_學寫API_如何撰寫 API 的單元測試

理解如何撰寫 API 的單元測試確實是一個需要逐步掌握的過程。下面我將詳細說明如何從基礎開始構思與撰寫單元測試,即使在不太理解的情況下,也可以一步步掌握整個過程。

1. 了解測試目的

首先,在撰寫單元測試之前,您必須理解為什麼要測試這個 API,這樣才能針對特定的目標撰寫測試。單元測試的目的是驗證您的代碼在不同的情況下是否都能正常運作,例如:

  • 確保 API 方法可以被成功呼叫。
  • 確保 API 返回的數據正確。
  • 處理各種可能的輸入或狀況,確保代碼的穩定性。

2. 宣告與測試設計的基礎

在進行測試之前,您需要對系統的結構有一定的了解:

  • 控制器PackageController 是我們要測試的控制器,它負責管理包裹的增刪改查操作。
  • 模型Package 模型表示每個包裹的基本信息,例如追蹤號、寄件人、收件人等。

3. 宣告測試環境

在單元測試中,我們需要設置好測試的環境,以便模擬應用程序中的控制器。這包括創建控制器實例並模擬其所依賴的所有服務或物件。以下是如何一步步構思和宣告測試環境:

  1. 理解控制器的依賴項

    • PackageController 的建構函數中,您可能會發現它依賴於某些外部服務,例如日誌記錄器 (ILogger)。
    • 所以,在單元測試中,我們需要創建這些依賴項的實例,這樣才能創建 PackageController 的實例。
  2. 宣告成員變數

    • **_controller**:這是我們要測試的控制器。
    • **_logger**:這是控制器依賴的日誌記錄器。
      1
      2
      private readonly PackageController _controller;
      private readonly ILogger<PackageController> _logger;
  3. 設置測試環境(建構函數)

    • 測試類的建構函數 PackageControllerTests(),用來初始化測試環境。通常,您需要通過依賴注入來創建控制器所需的外部資源。
    • 例如使用 LoggerFactory 創建日誌記錄器,然後用這個日誌記錄器來創建控制器的實例:
      1
      2
      3
      4
      5
      public PackageControllerTests()
      {
      _logger = new LoggerFactory().CreateLogger<PackageController>();
      _controller = new PackageController(_logger);
      }
    • 為何這麼做
      • 測試過程中,我們需要一個 PackageController 實例來調用其中的方法,這是測試的核心。
      • 控制器的建構函數可能需要某些服務(例如日誌記錄器),我們需要模擬這些服務來創建一個可測試的控制器實例。

4. 如何構思測試用例

構思測試用例的目標是確保各個 API 的功能運作正常。我們以 GetAllPackages() 方法為例,來說明如何構思測試。

  1. 理解方法的預期行為

    • GetAllPackages():這個方法應該返回一個包含所有包裹的列表,並且返回的 HTTP 狀態碼應該是 200 OK。
    • 如果數據是空的,應返回空列表,而不是錯誤或其他不合適的狀態碼。
  2. 撰寫測試的步驟

    • 在測試中通常包含三個部分:準備 (Arrange)執行 (Act) 和 **驗證 (Assert)**。

    • **準備 (Arrange)**:在這個階段,我們通常不需要額外的準備工作,因為我們的控制器已經在建構函數中初始化好了。

    • **執行 (Act)**:呼叫控制器的 GetAllPackages() 方法來取得結果。

      1
      var okResult = _controller.GetAllPackages();
    • **驗證 (Assert)**:檢查返回的結果是否符合預期。這裡有兩個測試:

      • 測試返回的結果是否為 200 OK

        1
        Assert.IsType<OkObjectResult>(okResult.Result);

        這一步是為了確保返回的 HTTP 狀態碼正確,這對於 API 的用戶來說非常重要。

      • 測試返回的數據是否正確

        1
        2
        3
        var okResult = _controller.GetAllPackages().Result as OkObjectResult;
        var items = Assert.IsType<List<Package>>(okResult.Value);
        Assert.Empty(items); // 預期初始時包裹列表為空

        這裡的測試是確保返回的數據類型是 List<Package>,並且在測試開始時這個列表應該是空的。

5. 如何構思單元測試即使不完全理解

如果您對測試不太理解,可以遵循以下步驟逐步進行:

  1. 參考現有的測試案例

    • 從其他已經存在的測試案例中學習如何構建測試,理解每個步驟的用途。
  2. 理解控制器的功能

    • 從控制器的代碼中了解每個方法的用途和行為,這樣您能更好地理解應該測試哪些場景。
  3. 測試基本場景

    • 最先測試的是基本場景,如:
      • 方法是否能正常返回?
      • 當列表是空的時候返回的數據是否符合預期?
      • 當有數據時,是否能正確返回?
  4. 逐步測試不同的情況

    • 例如,您可以考慮:
      • 如果用戶發送了無效的請求會怎麼樣?
      • 如果資料庫中已經有數據,返回的列表是否正確?
      • 如果新增重複的數據,系統應如何處理?

小結

撰寫單元測試需要理解系統的結構和每個 API 的用途。在不完全理解的情況下,您可以:

  • 參考已有代碼:觀察如何宣告和撰寫測試,理解每個步驟的目的。
  • 從最簡單的場景開始測試:例如,檢查返回的狀態碼和基本的數據型別。
  • 逐步學習代碼與框架:透過一次次的測試編寫,不斷熟悉框架及 API 的行為。

撰寫單元測試的過程是提高代碼質量、學習系統設計的一部分,即使一開始不完全理解,隨著您多次重複這個過程,理解會變得更加深入。希望這些建議能幫助您更好地構思和撰寫 API 的測試!