首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> ASP.NET 基礎 >> 關於ASP.NET

ASP.NET MVC 專案導入 TDD 測試驅動開發完整指南

     編輯:關於ASP.NET

測試驅動開發(TDD, Test-Driven Development)由 Kent Beck 推廣,核心循環為 紅-綠-重構。本文說明 TDD 核心概念、與傳統開發差異,並示範在 ASP.NET MVC 專案中如何落地實施。

三種開發模式比較

模式流程特點
Code → Bug Fix 寫碼 → 發現 Bug → 修補 無測試、品質不可控、維護成本高
Code → Unit Test → Bug Fix 寫碼 → 寫測試 → 執行測試 → 修補 有測試但為事後補充、覆蓋率難保證
TDD 寫測試 → 寫碼通過測試 → 重構 測試優先、設計導向、高覆蓋率、安全重構

TDD 核心循環:紅-綠-重構

  1. 紅:撰寫一個失敗的測試(定義預期行為)
  2. 綠:撰寫最少量程式碼讓測試通過
  3. 重構:在測試保護下優化程式碼結構、消除重複

TDD 目標導向比喻

TDD 紅綠重構循環圖

ASP.NET MVC 專案 TDD 實戰範例

情境:產品查詢服務

需求:依分類 ID 查詢產品,支援分頁,若分類不存在拋出例外。

步驟 1:建立測試專案

// 專案結構
MyApp.sln
├── MyApp.Web (MVC 專案)
├── MyApp.Core (領域模型、介面)
├── MyApp.Data (資料存取實作)
└── MyApp.Tests (單元測試專案 - 參考 xUnit/NUnit + Moq)

步驟 2:撰寫第一個失敗測試

public class ProductServiceTests
{
    private readonly Mock _mockRepo;
    private readonly ProductService _service;

    public ProductServiceTests()
    {
        _mockRepo = new Mock();
        _service = new ProductService(_mockRepo.Object);
    }

    [Fact]
    public void GetProductsByCategory_CategoryNotExists_ThrowsArgumentException()
    {
        // Arrange
        _mockRepo.Setup(r => r.CategoryExists(999)).Returns(false);

        // Act & Assert
        Assert.Throws(() => _service.GetProductsByCategory(999, 1, 10));
    }
}

執行測試 → 紅燈(尚未實作 ProductService)

步驟 3:實作最少程式碼通過測試

public class ProductService : IProductService
{
    private readonly IProductRepository _repo;

    public ProductService(IProductRepository repo)
    {
        _repo = repo;
    }

    public PagedList GetProductsByCategory(int categoryId, int page, int pageSize)
    {
        if (!_repo.CategoryExists(categoryId))
            throw new ArgumentException("分類不存在", nameof(categoryId));

        return _repo.GetProductsByCategory(categoryId, page, pageSize);
    }
}

執行測試 → 綠燈

步驟 4:新增正常情境測試並重構

[Fact]
public void GetProductsByCategory_ValidCategory_ReturnsPagedProducts()
{
    // Arrange
    var expectedProducts = new List { new Product { Id = 1, Name = "產品A" } };
    _mockRepo.Setup(r => r.CategoryExists(1)).Returns(true);
    _mockRepo.Setup(r => r.GetProductsByCategory(1, 1, 10))
             .Returns(new PagedList(expectedProducts, 1, 10, 1));

    // Act
    var result = _service.GetProductsByCategory(1, 1, 10);

    // Assert
    Assert.Single(result);
    Assert.Equal("產品A", result[0].Name);
}

步驟 5:Controller 整合測試

public class ProductControllerTests
{
    [Fact]
    public void CategoryProducts_ValidId_ReturnsPartialViewWithModel()
    {
        // Arrange
        var mockService = new Mock();
        mockService.Setup(s => s.GetProductsByCategory(1, 1, 10))
                   .Returns(new PagedList(new[] { new Product { Name = "Test" } }, 1, 10, 1));
        var controller = new ProductController(mockService.Object);

        // Act
        var result = controller.CategoryProducts(1, 1, 10) as PartialViewResult;

        // Assert
        Assert.NotNull(result);
        Assert.Equal("_ProductList", result.ViewName);
        var model = Assert.IsType>(result.Model);
        Assert.Single(model);
    }
}

ASP.NET MVC 中 TDD 關鍵實踐

層級測試重點工具建議
領域模型 商業規則、驗證邏輯、狀態轉換 xUnit + FluentAssertions
服務層 協調邏輯、異常處理、交易邊界 Moq / NSubstitute 模擬 Repository
Controller Action 結果型別、Model 綁定、導向、ViewName MVC 測試專用 Helper (如 MvcContrib.TestHelper)
路由 URL 對應 Controller/Action、參數解析 RouteDebugger / 自訂路由測試
過濾器 授權、例外處理、記錄行為 獨立測試 FilterAttribute 執行邏輯

常見誤區與對策

  • 測試寫太多實作細節 → 測試「行為」而非「方法呼叫」,避免重構時測試大量失效
  • 資料庫整合測試混入單元測試 → 單元測試必須快速、隔離、可重複;整合測試獨立專案執行
  • 追求 100% 覆蓋率 → 覆蓋率是副產品非目標,專注核心商業邏輯與邊界條件
  • 測試命名不清晰 → 採用 Method_Scenario_ExpectedBehavior 命名慣例

持續整合整合 TDD

  1. 建置伺服器(Azure DevOps / GitHub Actions / Jenkins)設定測試階段
  2. Pull Request 強制通過所有測試才能合併
  3. 測試執行時間超過 10 分鐘需拆分平行執行或優化
  4. 定期檢視測試趨勢圖,及早發現脆弱測試

總結

TDD 不僅是測試技術,更是軟體設計方法論。在 ASP.NET MVC 專案中導入 TDD,能強迫開發者從「使用者視角」設計 API、保持低耦合高內聚、建立安全重構網。雖初期投入較大,但長期維護成本顯著降低,是追求軟體品質團隊的必備實踐。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved