ASP.NET Core 单元测试:如何Mock Url.Page()
點擊上方藍字關注“汪宇杰博客”
導語
在 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);
}
汪宇杰博客
Azure | .NET |?微軟 MVP
無廣告,不賣課,做純粹的技術公眾號
總結
以上是生活随笔為你收集整理的ASP.NET Core 单元测试:如何Mock Url.Page()的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [Abp vNext 源码分析] - 1
- 下一篇: Hosting in .NET Core