嗯...问题更复杂,然后问题标题说。首先,我有一个 HtmlHelper 的扩展方法,它根据当前的路由参数生成带参数的 html 链接。也就是说,如果我在页面 .../page?param1=val1¶m2=val2
,当我调用我的方法时 ActionQuryLink
生成链接,例如 @Html.ActionQuryLink("link text", "action", new { param3 = "value3" })
我会得到一个链接到 <a href=".../page?param1=val1¶m2=val2¶m3=value3">link text</a>
.嗯,扩展类本身是:
public static class ActionLinkHelper
{
public static MvcHtmlString ActionQueryLink(this HtmlHelper htmlHelper, string linkText, string action)
{
return (ActionQueryLink(htmlHelper, linkText, action, null, null));
}
public static MvcHtmlString ActionQueryLink(this HtmlHelper htmlHelper, string linkText, string action, object routeValues)
{
/*line 16*/return (ActionQueryLink(htmlHelper, linkText, action, routeValues, null));
}
public static MvcHtmlString ActionQueryLink(this HtmlHelper htmlHelper, string linkText, string action, object routeValues, IDictionary<string, object> htmlAttributes)
{
var queryString = htmlHelper.ViewContext.HttpContext.Request.QueryString;
var newRoute = routeValues == null
? htmlHelper.ViewContext.RouteData.Values
: new RouteValueDictionary(routeValues);
foreach(string key in queryString.Keys)
{
if(!newRoute.ContainsKey(key))
newRoute.Add(key, queryString[key]);
}
/*line 32*/string generatedLink = HtmlHelper.GenerateLink(
htmlHelper.ViewContext.RequestContext,
htmlHelper.RouteCollection,
linkText,
null,
action,
null,
newRoute,
htmlAttributes);
return new MvcHtmlString(generatedLink);
}
}
主要问题是测试这个扩展方法
我的单元测试看起来像:
[TestClass]
public class ActionLinkHeplerTests
{
#region ActionQueryLink
[TestMethod]
public void ActionLinkHeplerShouldGenerateCorrectActionLink()
{
var mockHttpContext = new Mock<HttpContextBase>();
mockHttpContext.Setup(c => c.Request.QueryString).Returns(new NameValueCollection { { "param1", "value1" } });
mockHttpContext.Setup(c => c.Request.AppRelativeCurrentExecutionFilePath).Returns("~/");
mockHttpContext.Setup(c => c.Request.ApplicationPath).Returns("~/");
mockHttpContext.Setup(c => c.Request.CurrentExecutionFilePath).Returns("~/");
var mockProductRepository = new Mock<IProductRepository>();
mockProductRepository.Setup(p => p.GetCategory(It.IsAny<string>())).Returns(new Category());
var mockSettings = new Mock<ISettings>();
var categoryController = new CategoryController(mockProductRepository.Object, mockSettings.Object);
var mockViewDataContainer = new Mock<IViewDataContainer>();
mockViewDataContainer.Setup(e => e.ViewData).Returns(new ViewDataDictionary { { "action", "action" } });
var viewContext = new ViewContext
{
HttpContext = categoryController.HttpContext,
RequestContext = new RequestContext
{
HttpContext = mockHttpContext.Object,
RouteData = new RouteData()
}
};
var mockRouteHandler = new Mock<IRouteHandler>();
var helper = new HtmlHelper(viewContext, mockViewDataContainer.Object, new RouteCollection { { "action", new Route("controller/action", mockRouteHandler.Object) } });
var expected = new MvcHtmlString("");
/*line 51*/var actual = helper.ActionQueryLink("link text", "action", new {view = "list"});
Assert.AreEqual(expected, actual);
}
#endregion
}
我得到这样的异常:
Test method TestSite.UnitTests.Helpers.ActionLinkHeplerTests.ActionLinkHeplerShouldGenerateCorrectActionLink threw exception:
System.NullReferenceException: Object reference not set to an instance of an object.
和堆栈跟踪:
at System.Web.UI.Util.GetUrlWithApplicationPath(HttpContextBase context, String url)
at System.Web.Routing.RouteCollection.NormalizeVirtualPath(RequestContext requestContext, String virtualPath)
at System.Web.Routing.RouteCollection.GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
at System.Web.Mvc.RouteCollectionExtensions.GetVirtualPathForArea(RouteCollection routes, RequestContext requestContext, String name, RouteValueDictionary values, ref Boolean usingAreas)
at System.Web.Mvc.UrlHelper.GenerateUrl(String routeName, String actionName, String controllerName, RouteValueDictionary routeValues, RouteCollection routeCollection, RequestContext requestContext, Boolean includeImplicitMvcValues)
at System.Web.Mvc.UrlHelper.GenerateUrl(String routeName, String actionName, String controllerName, String protocol, String hostName, String fragment, RouteValueDictionary routeValues, RouteCollection routeCollection, RequestContext requestContext, Boolean includeImplicitMvcValues)
at System.Web.Mvc.HtmlHelper.GenerateLinkInternal(RequestContext requestContext, RouteCollection routeCollection, String linkText, String routeName, String actionName, String controllerName, String protocol, String hostName, String fragment, RouteValueDictionary routeValues, IDictionary`2 htmlAttributes, Boolean includeImplicitMvcValues)
at System.Web.Mvc.HtmlHelper.GenerateLink(RequestContext requestContext, RouteCollection routeCollection, String linkText, String routeName, String actionName, String controllerName, String protocol, String hostName, String fragment, RouteValueDictionary routeValues, IDictionary`2 htmlAttributes)
at System.Web.Mvc.HtmlHelper.GenerateLink(RequestContext requestContext, RouteCollection routeCollection, String linkText, String routeName, String actionName, String controllerName, RouteValueDictionary routeValues, IDictionary`2 htmlAttributes)
at Core.Helpers.ActionLinkHelper.ActionQueryLink(HtmlHelper htmlHelper, String linkText, String action, Object routeValues, IDictionary`2 htmlAttributes) in ActionLinkHelper.cs: line 32
at Core.Helpers.ActionLinkHelper.ActionQueryLink(HtmlHelper htmlHelper, String linkText, String action, Object routeValues) in ActionLinkHelper.cs: line 16
at TestSite.UnitTests.Helpers.ActionLinkHeplerTests.ActionLinkHeplerShouldGenerateCorrectActionLink() in ActionLinkHeplerTests.cs: line 51
好吧,对于这样一批代码我真的很抱歉。
但我正在处理这个问题大约 3 天。如您所见,错误甚至不发生在某些 MVC 库中,而是发生在 System.Web.UI.Util
。 .即使我能找到 System.Web.UI.Util
源并将其作为另一个项目添加到我的解决方案中,我无法强制 MVC 框架使用此项目而不是 System.Web.UI.Util
来自全局组装现金。老实说,在我的解决方案中将 MVC 从 GAC 替换为 MVC 的源项目甚至非常困难,因为它非常复杂,有很多依赖关系,当我尝试这样做时,我遇到了很多错误,其中大部分是已经使用来自全局装配现金的 MVC 装配的外部库。同样最重要的是,我的辅助方法在我的项目中运行良好,它仅在测试时调用异常。所以我的建议是helper的测试条件不全或者可能是错误的。总而言之,我的问题是如何使用 Moq 为我的 html 帮助程序扩展方法模拟正确的条件,或者,是否还有其他问题?
最佳答案
事实证明,要测试依赖路由信息的助手,需要模拟以下 RequestContext.HttpContext
方法:
RequestContext.HttpContext.Request.ApplicationPath
- 应返回类似于根路径的内容(即@"/"
)RequestContext.HttpContext.Response.ApplyAppPathModifier
- 可以简单地返回其输入参数:
示例:
request.Setup(r => r.ApplicationPath).Returns(@"/");
response.Setup(r => r.ApplyAppPathModifier(It.IsAny<string>()))
.Returns((string s) => s);
关于c# - 如果我在测试时在 System.Web.UI.Util 处遇到异常,如何对我的 HtmlHelper 扩展方法进行单元测试?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12401749/