單元測試中如何Mock HttpContext

最近團隊有小夥伴問在單元測試中如何Mock HttpContext. 這是一個好問題,整理了一個實現方案分享給大家。

在C#中,尤其是在單元測試場景下,模擬(Mocking)HttpContext 是一種常見的做法。這允許我們在沒有實際HTTP請求的情況下測試與HTTP上下文相關的代碼。

爲了模擬HttpContext,我們通常會使用像Moq這樣的庫,它是.NET中一個流行的模擬框架。
以下是一個簡單的示例,展示瞭如何使用Moq來模擬一個HttpContext:
首先,你需要安裝Moq庫。如果你使用的是.NET Core或.NET 5/6/7/8等較新版本,你可以通過NuGet包管理器來安裝它:

dotnet add package Moq

或者,在Visual Studio中,你可以通過NuGet包管理器UI來搜索並安裝Moq。

安裝完成後,編寫以下代碼來創建一個模擬的HttpContext.

using System.Security.Claims;
using System.Web;
using Moq;

// 創建一個模擬的HttpContext
var mockContext = new Mock<HttpContextBase>();

// 模擬HttpRequest
var mockRequest = new Mock<HttpRequestBase>();
mockRequest.Setup(r => r.ApplicationPath).Returns("/");
mockRequest.Setup(r => r.ServerVariables).Returns(new System.Collections.Specialized.NameValueCollection());
mockContext.Setup(c => c.Request).Returns(mockRequest.Object);

// 模擬HttpResponse
var mockResponse = new Mock<HttpResponseBase>();
mockResponse.Setup(r => r.Cache).Returns(new HttpCachePolicyBase());
mockContext.Setup(c => c.Response).Returns(mockResponse.Object);

// 模擬HttpSessionState
var mockSession = new Mock<HttpSessionStateBase>();
mockSession.Setup(s => s["MySessionItem"]).Returns("SessionValue");
mockContext.Setup(c => c.Session).Returns(mockSession.Object);

// 模擬HttpServerUtility
var mockServer = new Mock<HttpServerUtilityBase>();
mockContext.Setup(c => c.Server).Returns(mockServer.Object);

// 模擬HttpUser
var mockUser = new Mock<IPrincipal>();
var mockIdentity = new Mock<IIdentity>();
mockIdentity.Setup(i => i.Name).Returns("User");
mockIdentity.Setup(i => i.IsAuthenticated).Returns(true);
mockUser.Setup(u => u.Identity).Returns(mockIdentity.Object);
mockContext.Setup(c => c.User).Returns(mockUser.Object);

// 現在你可以使用 mockContext.Object 來作爲你的HttpContextBase對象了
var httpContext = mockContext.Object;

// 使用示例:
var userName = httpContext.User.Identity.Name; // 返回 "User"
var isAuthenticated = httpContext.User.Identity.IsAuthenticated; // 返回 true
var mySessionItem = httpContext.Session["MySessionItem"]; // 返回 "SessionValue"

 更進一步,我們可以把這個HttpContext的mock封裝成一個服務,團隊其他的小夥伴也可以一起使用。

 so,爲了使其更加模塊化和可重用,我們可以將這些模擬的創建過程封裝到一個方法中,或者創建一個專門的服務類來提供HttpContextBase的模擬實例。

using System.Collections.Specialized;
using System.Security.Principal;
using System.Web;
using Moq;

public static class MockHttpContextService
{
    public static HttpContextBase CreateMockHttpContext(
        string userName = "User",
        bool isAuthenticated = true,
        string sessionKey = "MySessionItem",
        object sessionValue = null,
        string applicationPath = "/",
        NameValueCollection serverVariables = null)
    {
        var mockContext = new Mock<HttpContextBase>();

        // 模擬HttpRequest
        var mockRequest = new Mock<HttpRequestBase>();
        mockRequest.Setup(r => r.ApplicationPath).Returns(applicationPath);
        mockRequest.Setup(r => r.ServerVariables).Returns(serverVariables ?? new NameValueCollection());
        mockContext.Setup(c => c.Request).Returns(mockRequest.Object);

        // 模擬HttpResponse
        var mockResponse = new Mock<HttpResponseBase>();
        mockResponse.Setup(r => r.Cache).Returns(new HttpCachePolicyBase());
        mockContext.Setup(c => c.Response).Returns(mockResponse.Object);

        // 模擬HttpSessionState
        var mockSession = new Mock<HttpSessionStateBase>();
        if (sessionKey != null)
        {
            mockSession.Setup(s => s[sessionKey]).Returns(sessionValue);
        }
        mockContext.Setup(c => c.Session).Returns(mockSession.Object);

        // 模擬HttpServerUtility
        var mockServer = new Mock<HttpServerUtilityBase>();
        mockContext.Setup(c => c.Server).Returns(mockServer.Object);

        // 模擬HttpUser
        var mockUser = new Mock<IPrincipal>();
        var mockIdentity = new Mock<IIdentity>();
        mockIdentity.Setup(i => i.Name).Returns(userName);
        mockIdentity.Setup(i => i.IsAuthenticated).Returns(isAuthenticated);
        mockUser.Setup(u => u.Identity).Returns(mockIdentity.Object);
        mockContext.Setup(c => c.User).Returns(mockUser.Object);

        return mockContext.Object;
    }
}

創建模擬HttpContext對象時傳入自定義參數:

var httpContext = MockHttpContextService.CreateMockHttpContext(
    userName: "CustomUser",
    isAuthenticated: false,
    sessionKey: "CustomSessionItem",
    sessionValue: "CustomSessionValue",
    applicationPath: "/MyApp",
    serverVariables: new NameValueCollection { { "SERVER_NAME", "localhost" } }
);

// 使用示例:
var userName = httpContext.User.Identity.Name; // 返回 "CustomUser"
var isAuthenticated = httpContext.User.Identity.IsAuthenticated; // 返回 false
var mySessionItem = httpContext.Session["CustomSessionItem"]; // 返回 "CustomSessionValue"
var appPath = httpContext.Request.ApplicationPath; // 返回 "/MyApp"
var serverName = httpContext.Request.ServerVariables["SERVER_NAME"]; // 返回 "localhost"

以上是單元測試中如何Mock HttpContext的分享,希望能幫助到大家。

 

周國慶

2024/1/24

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章