首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計疑難解答

Moq 模擬 HttpContext 單元測試:ASP.NET FormsAuthentication 完整範例

     編輯:程式設計疑難解答

被測試程式碼


public static VMERPUser Me {
    get {
        var identity = HttpContext.Current.User.Identity as FormsIdentity;
        if (identity != null) {
            var ticket = identity.Ticket;
            return JsonConvert.DeserializeObject(ticket.UserData);
        }
        return null;
    }
}

Moq 完整測試程式碼


[TestMethod]
public void Me_ReturnsUser_WhenValidTicket() {
    // 1. 準備假資料
    var userData = JsonConvert.SerializeObject(new VMERPUser { Id = 1, Name = "Test" });
    var ticket = new FormsAuthenticationTicket(1, "user", DateTime.Now, DateTime.Now.AddHours(1), false, userData);
    var identity = new FormsIdentity(ticket);
    var principal = new GenericPrincipal(identity, new string[0]);

    // 2. Mock HttpContext
    var mockContext = new Mock();
    mockContext.Setup(c => c.User).Returns(principal);
    mockContext.Setup(c => c.Request).Returns(new Mock().Object);
    mockContext.Setup(c => c.Response).Returns(new Mock().Object);

    // 3. 設定 Current (靜態屬性需用 HttpContext.Current = ...)
    HttpContext.Current = new HttpContext(
        new SimpleWorkerRequest("", "", new StringWriter()),
        mockContext.Object
    );
    // 或使用 MvcContrib.TestHelper 的 TestControllerBuilder

    // 4. 驗證
    var result = YourClass.Me;
    Assert.IsNotNull(result);
    Assert.AreEqual(1, result.Id);
    Assert.AreEqual("Test", result.Name);
}

關鍵點解析

步驟說明
FormsAuthenticationTicketUserData 欄位存放序列化後的使用者物件
FormsIdentity包裝 Ticket,實作 IIdentity
GenericPrincipal包裝 Identity + 角色陣列
HttpContext.Current靜態屬性,測試前需手動注入 Mock 物件

現代替代方案 (ASP.NET Core)


// Controller 內直接注入 IHttpContextAccessor
public class MyController : Controller {
    private readonly IHttpContextAccessor _http;
    public MyController(IHttpContextAccessor http) => _http = http;

    public VMERPUser Me => 
        _http.HttpContext?.User?.Identity is FormsIdentity id
            ? JsonConvert.DeserializeObject(((FormsIdentity)id).Ticket.UserData)
            : null;
}

// 測試時直接 Mock IHttpContextAccessor
var mockAccessor = new Mock();
mockAccessor.Setup(a => a.HttpContext.User).Returns(principal);

常見坑

  • ❌ 忘記 HttpContext.Current = ... → NullReferenceException
  • ❌ SimpleWorkerRequest 建構子參數錯誤 → 導致 Context 初始化失敗
  • ✅ 使用 MvcContrib.TestHelper 或 AspNetCore.TestHost 簡化設定
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved