Search code examples
c#asp.net-coremstest

Unit testing UrlHelper extensions


I have written several extension methods for the UrlHelper in my ASP.NET Core project. Now I would like to write unit tests for them. However, many of my extension methods leverage the UrlHelper's methods (for example, Action), so I need to pass a working UrlHelper to the this argument (or a working UrlHelper to call the methods on).

How can I instantiate a working UrlHelper? I tried this:

        Mock<HttpContext> mockHTTPContext = new Mock<HttpContext>();
        Microsoft.AspNetCore.Mvc.ActionContext actionContext = new Microsoft.AspNetCore.Mvc.ActionContext(
            new DefaultHttpContext(), 
            new RouteData(), 
            new ActionDescriptor());
        UrlHelper urlHelper = new UrlHelper(actionContext);

        Guid theGUID = Guid.NewGuid();

        Assert.AreEqual("/Admin/Users/Edit/" + theGUID.ToString(), UrlHelperExtensions.UserEditPage(urlHelper, theGUID));

It crashes (Test method Test.Commons.Admin.UrlHelperTests.URLGeneration threw exception: System.ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection. Parameter name: index) with this call stack:

   at System.Collections.Generic.List`1.get_Item(Int32 index)
   at Microsoft.AspNetCore.Mvc.Routing.UrlHelper.GetVirtualPathData(String routeName, RouteValueDictionary values)
   at Microsoft.AspNetCore.Mvc.Routing.UrlHelper.Action(UrlActionContext actionContext)
   at Microsoft.AspNetCore.Mvc.UrlHelperExtensions.Action(IUrlHelper helper, String action, String controller, Object values)
   at <MY PROEJCT>.UrlHelperExtensions.UserEditPage(IUrlHelper helper, Guid i_userGUID) 
   at <MY TEST>.URLGeneration()

An example of the extension methods is the following:

    public static string UserEditPage(this IUrlHelper helper, Guid i_userGUID)
    {
        return helper.Action(
            nameof(UsersController.EditUser), 
            "Users", 
            new { id = i_userGUID });
    }

Solution

  • Your best bet to test UrlHelper extensions would be to mock IUrlHelper, e.g. using Moq:

    // arrange
    UrlActionContext actual = null;
    var userId = new Guid("52368a14-23fa-4c7f-a9e9-69b44fafcade");
    
    // prepare action context as necessary
    var actionContext = new ActionContext
    {
        ActionDescriptor = new ActionDescriptor(),
        RouteData = new RouteData(),
    };
    
    // create url helper mock
    var urlHelper = new Mock<IUrlHelper>();
    urlHelper.SetupGet(h => h.ActionContext).Returns(actionContext);
    urlHelper.Setup(h => h.Action(It.IsAny<UrlActionContext>()))
        .Callback((UrlActionContext context) => actual = context);
    
    // act
    var result = urlHelper.Object.UserEditPage(userId);
    
    // assert
    urlHelper.Verify();
    Assert.Equal("EditUser", actual.Action);
    Assert.Equal("Users", actual.Controller);
    Assert.Null(actual.RouteName);
    
    var values = new RouteValueDictionary(actual.Values);
    Assert.Equal(userId, values["id"]);
    

    Check out the UrlHelperExtensionsTest of ASP.NET Core to get some ideas on how this works in detail.