iT邦幫忙

2024 iThome 鐵人賽

DAY 28
0
生成式 AI

從系統設計切入,探索 GenAI 在企業中的實踐系列 第 28

[Day28] 測試驅動開發 (TDD):實現穩定性與快速迭代的開發模式

  • 分享至 

  • xImage
  •  

隨著服務規模的擴展和 API 數量的增加,系統的穩定性變得愈發重要。在**生成式AI(GenAI)**的開發中,企業級項目通常需要快速迭代以適應市場需求變化,這對開發速度和系統穩定性提出了雙重挑戰。為了在快速交付的同時確保系統能穩定運行,開發者需要一套高效且可靠的開發方法。

此時,同時進行開發與測試變得十分重要。這是確保功能穩定與減少錯誤風險的有效途徑,而這正是 **TDD(Test-Driven Development, 測試驅動開發)**的強項。TDD 是一種軟體開發方法,其核心理念是先撰寫測試程式碼,再開發功能程式。這種方法確保每個功能在開發過程中都經過測試驗證,從而減少程式錯誤並提升系統的穩定性。

TDD 的工作流程通常分為三個步驟:撰寫測試(紅燈)、編寫程式碼讓測試通過(綠燈)、重構程式碼。這樣的迭代循環不僅幫助開發者逐步完善系統,還能保持程式的可測性與可維護性,特別適合應對GenAI項目中快速變更和穩定性需求的挑戰。

前備知識

在實踐 TDD 之前,我們需要具備一些基本知識。首先,必須熟悉單元測試的原則,這包括理解如何針對最小的模組(如方法或類)進行獨立驗證。單元測試應該在隔離環境中執行,不依賴於外部資源,如數據庫或API,這能確保在系統變更時每個模組都能正常運行,減少潛在的回歸問題。

除了隔離性,測試覆蓋率同樣重要。高覆蓋率意味著測試必須涵蓋所有可能的邊界條件和錯誤情境,確保代碼在各種情況下都能正確執行。良好的單元測試應該快速執行,幫助開發者在每次變更後迅速驗證系統,從而加快開發迭代的效率。

此外,依賴注入Mock 技術是提升測試靈活性的重要工具。依賴注入允許我們在開發中將外部依賴(如服務或資源)動態替換,這使得代碼更加模組化,並減少系統的耦合度。在測試中,依賴注入結合Mock技術,能模擬外部服務或資源,避免與真實環境交互,從而專注於測試核心邏輯。

TDD 範例:文本摘要生成 API

接下來,我們將通過一個實際範例來展示 TDD 的流程。假設我們正在開發一個生成文本摘要的功能,要求摘要不能超過100個字。以下是如何使用 TDD 來逐步完成這個功能的示例。

Step 1: 撰寫失敗的測試(紅燈)

首先,我們編寫一個測試來驗證我們的摘要生成 API 能否生成不超過 100 字的摘要。這個測試會用 Mock 來模擬摘要服務,並專注於測試 API 的行為。

import unittest
from unittest.mock import Mock

class TestSummaryAPI(unittest.TestCase):

    def test_summary_should_be_less_than_100_characters(self):
        # Arrange: 初始化條件
        mock_summary_service = Mock()
        mock_summary_service.generate_summary.return_value = "AI transforms technology."

        article_text = "This is a long article about AI and how it changes the world of technology..."
        api = SummaryAPI(mock_summary_service)

        # Act: 調用API生成摘要
        response = api.generate_summary(article_text)

        # Assert: 驗證摘要長度
        self.assertTrue(len(response) <= 100)

在這裡,我們使用Mock來模擬SummaryService,並通過TDD的流程首先編寫測試。因為我們尚未實現SummaryAPI,測試會失敗(紅燈)。

Step 2: 編寫讓測試通過的代碼(綠燈)

接下來,我們實現 SummaryAPI,讓測試能夠通過。注意這裡我們專注於簡單實現 API 層的行為。

class SummaryAPI:

    def __init__(self, summary_service):
        self.summary_service = summary_service

    def generate_summary(self, article_text):
        return self.summary_service.generate_summary(article_text)

Step 3: 重構並完善服務邏輯

此時,簡單的 SummaryAPI 已經可以通過測試。接下來,我們需要深入實現具體的摘要生成邏輯,並加入新的測試案例。

class SummaryService:

    def generate_summary(self, article_text):
        if len(article_text) > 100:
            return article_text[:100]
        return article_text

並增加對其他情境的測試,例如當文章少於 100 字時,應返回完整的文章。

def test_summary_should_return_full_text_if_less_than_100_characters(self):
    # Arrange
    short_text = "Short article."
    mock_summary_service = Mock()
    mock_summary_service.generate_summary.return_value = short_text
    api = SummaryAPI(mock_summary_service)

    # Act
    response = api.generate_summary(short_text)

    # Assert
    self.assertEqual(short_text, response)

Step 4: 增加更多測試場景

我們可以繼續增加測試來處理不同的場景和邊界條件。例如,處理空文章、特殊字符或文章過長的情況,這些場景都可以通過 TDD 的方式一步步測試和實現。這樣不僅能保證我們的 API 邏輯穩定,還能避免未來功能擴展時引入錯誤。


TDD 不僅僅是一種測試方法,更是一種開發思維,能夠幫助我們構建穩定、可擴展的系統。通過這個 TDD 範例,我們展示了如何從撰寫失敗的測試開始,逐步實現功能並進行代碼重構。在 GenAI 開發中,這種測試驅動的方式能確保每個模組都經過充分的驗證,並且代碼結構保持簡潔且易於維護。依賴注入與 Mock 技術進一步提高了測試的靈活性,讓我們能夠在不依賴真實外部服務的情況下進行有效測試。


上一篇
[Day27] OpenAPI 規範:基礎介紹與 FastAPI 的自動化 API 配置
下一篇
[Day29] 指標驅動開發 (MDD):如何通過 RAGAs 量化 RAG 生成效果
系列文
從系統設計切入,探索 GenAI 在企業中的實踐30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言