前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >ASP.NET Core 单元测试:如何Mock Url.Page()

ASP.NET Core 单元测试:如何Mock Url.Page()

作者头像
Edi Wang
发布2021-04-29 17:32:11
1K0
发布2021-04-29 17:32:11
举报
文章被收录于专栏:汪宇杰博客汪宇杰博客

点击上方蓝字关注“汪宇杰博客”

导语

在 ASP.NET Core 中,当你在 UrlHelperExtensions 类上使用扩展方法时,很难在单元测试中编写Mock。因为Moq框架不支持模拟扩展方法。

问题

例如,我的博客代码中使用了 Url.Page() 方法:

var callbackUrl = Url.Page("/Index", null, null, Request.Scheme);

但是单元测试中,像这样 Mock 就会爆:

var mockUrlHelper = new Mock<IUrlHelper>(MockBehavior.Strict);mockUrlHelper.Setup(x => x.Page("/Index", null, null, It.IsAny<string>())).Returns("callbackUrl").Verifiable();

爆炸现场

System.NotSupportedException : Unsupported expression: x => x.Page("/Index", null, null, It.IsAny<string>()) Extension methods (here: UrlHelperExtensions.Page) may not be used in setup / verification expressions.

解决方法

我们需要 Mock 这个拓展方法调用的底层方法。在本案例中,底层方法是

Microsoft.AspNetCore.Mvc.IUrlHelper.RouteUrl(UrlRouteContext routeContext)

我是怎么知道的呢?很简单,.NET 都已经开源多少年了,直接看一眼源代码就能知道微软如何单元测试 UrlHelperExtensions。

https://source.dot.net/

从微软的代码里复制两个助手方法

private Mock<IUrlHelper> CreateMockUrlHelper(ActionContext context = null)

{

context ??= GetActionContextForPage("/Page");

var urlHelper = _mockRepository.Create<IUrlHelper>();

urlHelper.SetupGet(h => h.ActionContext)

.Returns(context);

return urlHelper;

}

private static ActionContext GetActionContextForPage(string page)

{

return new()

{

ActionDescriptor = new()

{

RouteValues = new Dictionary<string, string>

{

{ "page", page },

}

},

RouteData = new()

{

Values =

{

[ "page" ] = page

}

}

};

}

修改我们的单元测试

var mockUrlHelper = CreateMockUrlHelper();mockUrlHelper.Setup(h => h.RouteUrl(It.IsAny<UrlRouteContext>())).Returns("callbackUrl");

现在单元测试就能顺利跑过了!

完整的单元测试代码见下方供参考:

[Test]

public async Task SignOutAAD()

{

_mockOptions.Setup(m => m.Value).Returns(new AuthenticationSettings

{

Provider = AuthenticationProvider.AzureAD

});

var mockUrlHelper = CreateMockUrlHelper();

mockUrlHelper.Setup(h => h.RouteUrl(It.IsAny<UrlRouteContext>()))

.Returns("callbackUrl");

var ctx = new DefaultHttpContext();

var ctl = CreateAuthController();

ctl.ControllerContext = new() { HttpContext = ctx };

ctl.Url = mockUrlHelper.Object;

var result = await ctl.SignOut();

Assert.IsInstanceOf(typeof(SignOutResult), result);

}

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-04-26,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 汪宇杰博客 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档