Search code examples
jsonasp.net-mvc-4moqjson.neturl.action

Url.Action becomes null when in JSON string


Bit of a noob with testing so please bear with me,

I have a controller that returns a JsonResult that contains a string calculated by Url.Action like this:

 public ActionResult GetResult(SomeModel model)
 {
     if (ModelState.IsValid)
     {
         return Json(new { redirectTo = Url.Action("Index", "Profile") });
     }
 }

And the application works just fine when I use that result using jQuery.

However during my unit testing I have issues because when I test the content of the Json string the redirectTo value appears to be "null" even though it's not null in the application itself.

My test method looks a bit like this:

 [Test]
 public void GetResult_Success()
 {
     var result = controller.GetResult(new SomeModel());

     Assert.IsNotNull(result);
     Assert.IsInstanceOf<JsonResult>(result);

     var jsonResult = result as JsonResult;
     var jsonObject = JsonConvert.DeserializeAnonymousType(new JavaScriptSerializer().Serialize(jsonResult.Data), new
     {
         redirectTo = string.Empty
     });

     Assert.AreEqual("Profile/Index", jsonObject.redirectTo);
 }

This fails because jsonObject.redirectTo is null. If in my controller I change Url.Action into "Profile/Index" the test passes. However Url.Action("Index", "Profile") fails because it becomes null only in unit testing.

If I try to set up the route values in the Context setup for the tests it complains that they are already registered. I'm using Moq. Any idea what I need to set up? Many thanks in advance


Solution

  • The answer can be found at this link

    Code copied for more permanence:

    public static void SetupWithHttpContextAndUrlHelper(this Controller controller)
    {
        var routes = new RouteCollection();
        MvcApplication.RegisterRoutes(routes);
    
        //setup request
        var requestContextMock = new Mock<HttpRequestBase>();
        requestContextMock.Setup(r => r.AppRelativeCurrentExecutionFilePath).Returns("/");
        requestContextMock.Setup(r => r.ApplicationPath).Returns("/");
    
        //setup response
        var responseMock = new Mock<HttpResponseBase>();
        responseMock.Setup(s => s.ApplyAppPathModifier(It.IsAny<string>())).Returns<string>(s => s);
    
        //setup context with request and response
        var httpContextMock = new Mock<HttpContextBase>();
        httpContextMock.Setup(h => h.Request).Returns(requestContextMock.Object);
        httpContextMock.Setup(h => h.Response).Returns(responseMock.Object);
    
        controller.ControllerContext = new ControllerContext(httpContextMock.Object, new RouteData(), controller);
        controller.Url = new UrlHelper(new RequestContext(httpContextMock.Object, new RouteData()), routes);
    }