测试Razor Page的OnGetCurrencyAsync方法时如何模拟Request?
解决Razor页面单元测试中Request为null的问题
你遇到的问题根源是:Razor页面模型的Request、Url等属性依赖于HttpContext,直接实例化HomeModel时这些上下文属性不会自动初始化,导致调用Request.Headers时出现空引用错误。下面是具体的解决步骤和修改后的测试代码:
关键配置点
- 模拟
HttpContext并设置Request的Referer请求头 - 配置
UrlHelper,满足Url.IsLocalUrl和Url.Content的调用需求 - 给
HomeModel实例赋值HttpContext和Url属性 - 模拟
ICurrentUserService的相关方法(原方法中会调用,避免额外空引用)
修改后的完整测试代码
[Fact] public async Task OnGetCurrencyAsync_ValidReferer_RedirectsToReferer() { // 测试用的Referer地址 var refererUrl = "https://localhost:44317/paris"; var testCurrency = "EUR"; // 模拟依赖服务 var currentUserService = new Mock<ICurrentUserService>(); var options = new Mock<IOptions<Core.Configuration.AppSettings>>(); var navigationMenu = new Mock<INavigationMenu>(); var productModelService = new Mock<IProductModelService>(); var userSavedProductRepository = new Mock<IUserSavedProductRepository>(); var userSavedProductService = new Mock<IUserSavedProductService>(); // 模拟HttpContext和Request var mockHttpContext = new Mock<HttpContext>(); var mockRequest = new Mock<HttpRequest>(); // 设置Referer请求头 var headers = new HeaderDictionary(); headers["Referer"] = refererUrl; mockRequest.Setup(r => r.Headers).Returns(headers); // 设置Request的Scheme和Host,用于Url.IsLocalUrl判断 mockRequest.Setup(r => r.Scheme).Returns("https"); mockRequest.Setup(r => r.Host).Returns(HostString.FromUriComponent(refererUrl)); mockHttpContext.Setup(c => c.Request).Returns(mockRequest.Object); // 创建ActionContext并初始化UrlHelper var actionContext = new ActionContext(mockHttpContext.Object, new RouteData(), new PageActionDescriptor()); var urlHelper = new UrlHelper(actionContext); // 实例化HomeModel并赋值上下文属性 var homePage = new HomeModel( currentUserService.Object, options.Object, navigationMenu.Object, productModelService.Object, userSavedProductService.Object, userSavedProductRepository.Object) { HttpContext = mockHttpContext.Object, Url = urlHelper }; // 模拟CurrentUserService的方法,返回测试Session var testSession = new UserSession { Currency = "USD" }; currentUserService.Setup(s => s.GetOrInitializeSessionAsync(It.IsAny<CancellationToken>())) .ReturnsAsync(testSession); currentUserService.Setup(s => s.SetSession(It.IsAny<UserSession>(), It.IsAny<CancellationToken>())) .Returns(Task.CompletedTask); // 执行测试方法 var result = await homePage.OnGetCurrencyAsync(testCurrency, CancellationToken.None); // 断言验证 var redirectResult = Assert.IsType<RedirectResult>(result); Assert.Equal(refererUrl, redirectResult.Url); // 验证Session的Currency是否被更新 Assert.Equal(testCurrency, testSession.Currency); currentUserService.Verify(s => s.SetSession(testSession, It.IsAny<CancellationToken>()), Times.Once); }
代码说明
- HttpContext模拟:通过
Mock<HttpContext>和Mock<HttpRequest>设置请求头和请求基本信息,确保Request不为null,且能正确获取Referer值。 - UrlHelper配置:基于模拟的
ActionContext创建UrlHelper,赋值给HomeModel的Url属性,保证Url.IsLocalUrl和Url.Content能正常工作。 - 服务模拟完善:补充了
ICurrentUserService的方法模拟,避免测试过程中因未模拟服务方法导致的额外错误,同时可以验证Session是否被正确更新。
内容的提问来源于stack exchange,提问作者advapi
相关产品推荐
相关产品推荐

