• 单元测试中如何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();
    
    // 模拟HttpRequest
    var mockRequest = new Mock();
    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();
    mockResponse.Setup(r => r.Cache).Returns(new HttpCachePolicyBase());
    mockContext.Setup(c => c.Response).Returns(mockResponse.Object);
    
    // 模拟HttpSessionState
    var mockSession = new Mock();
    mockSession.Setup(s => s["MySessionItem"]).Returns("SessionValue");
    mockContext.Setup(c => c.Session).Returns(mockSession.Object);
    
    // 模拟HttpServerUtility
    var mockServer = new Mock();
    mockContext.Setup(c => c.Server).Returns(mockServer.Object);
    
    // 模拟HttpUser
    var mockUser = new Mock();
    var mockIdentity = new Mock();
    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();
    
            // 模拟HttpRequest
            var mockRequest = new Mock();
            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();
            mockResponse.Setup(r => r.Cache).Returns(new HttpCachePolicyBase());
            mockContext.Setup(c => c.Response).Returns(mockResponse.Object);
    
            // 模拟HttpSessionState
            var mockSession = new Mock();
            if (sessionKey != null)
            {
                mockSession.Setup(s => s[sessionKey]).Returns(sessionValue);
            }
            mockContext.Setup(c => c.Session).Returns(mockSession.Object);
    
            // 模拟HttpServerUtility
            var mockServer = new Mock();
            mockContext.Setup(c => c.Server).Returns(mockServer.Object);
    
            // 模拟HttpUser
            var mockUser = new Mock();
            var mockIdentity = new Mock();
            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

  • 相关阅读:
    NUMPY
    【 Tkinter界面-练习04】 画板作画详细揭示
    C++回顾从入门开始
    武汉某母婴用品公司 - 集简云连接ERP和营销系统,实现库存管理的自动化
    Java - Hutool 获取 HttpRequest:Header、Body、ParamMap 等利器
    docker安装
    绝地求生【商城更新】WIA联名上架//专属商店下架
    DELETE、TRUNCATE 和 DROP 在MySQL中的区别及使用示例
    如何快速发现panic
    echarts 配置方法使用记录
  • 原文地址:https://www.cnblogs.com/tianqing/p/17983832