Well ... the problem is more complicated, then the question title says. First of all, I have an extension method for HtmlHelper that generates an html link with parameters based on the current route parameters. Namely, if I am on the page .../page?param1=val1¶m2=val2 when I call my ActionQuryLink method to create a link, for example @Html.ActionQuryLink("link text", "action", new { param3 = "value3" }) Iβll get a link to <a href=".../page?param1=val1¶m2=val2¶m3=value3">link text</a> . Well, the extension class itself:
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) { 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]); } string generatedLink = HtmlHelper.GenerateLink( htmlHelper.ViewContext.RequestContext, htmlHelper.RouteCollection, linkText, null, action, null, newRoute, htmlAttributes); return new MvcHtmlString(generatedLink); } }
The main problem is checking this extension method
my unit test is as follows:
[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 }
And I get this exception:
Test method TestSite.UnitTests.Helpers.ActionLinkHeplerTests.ActionLinkHeplerShouldGenerateCorrectActionLink threw exception: System.NullReferenceException: Object reference not set to an instance of an object.
and stack trace:
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
Well, I'm really sorry for such a batch of code. But I have been working on this problem for about 3 days. Since you can see that the error is not even found in some MVC library, but in System.Web.UI.Util . Even if I could find the sources of System.Web.UI.Util and add it to my solution as another project, I could not get the MVC infrastructure to use this project instead of System.Web.UI.Util from the global assembly funds. Honestly, itβs even very difficult to replace MVC from the GAC project to MVC in my solution, because it is very complex, there are a lot of dependencies, and when I tried to do this, I had a lot of errors, and most of them were from external libraries, which already use MVC assembly from global assembly funds. Also the most important thing is that my helper method works fine in my project, it throws exceptions only during testing. Therefore, my suggestion is that the test conditions for the assistant are not complete or probably incorrect. Summary, my question is, how can I make fun of the right conditions for my html helper extension method using Moq, or maybe there is another problem?