This is a migrated thread and some comments may be shown as answers.

More completely mocking the ControllerContext

1 Answer 106 Views
General Discussions
This is a migrated thread and some comments may be shown as answers.
Jonathan
Top achievements
Rank 1
Jonathan asked on 16 Mar 2016, 07:20 PM

I have MockupController class with Just Mock and using the template found here

http://blog.johnnyreilly.com/2013/02/unit-testing-mvc-controllers-mocking.html#comment-2562756456

Tthe MockController class file that also includes the ability to mock a custom identity class that inherits from IIdentity.

While this class is useful it's still not mocking all the necessary aspects including routing.

Currently an error is being thrown with these two lines of the application code

 

                        UrlHelper u = new UrlHelper(ControllerContext.RequestContext);
                        string url = u.Action("Results", new { id = v.VerificationID });

 

Any ideas?

 

Here is the MockupController class

using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Telerik.JustMock;
using Telerik.JustMock.AutoMock;
using System.Web;
using QmostWeb.Controllers;
using System.Web.Mvc;
using System.Web.Routing;
using System.Security.Principal;
using QmostWeb;
using QmostWeb.Models;
using QmostBase;
using System.Collections.Specialized;

namespace QmostWebTest
{
    public static class ControllerMockup
    {
        #region Mock HttpContext factories
        public static HttpContextBase MockHttpContext()
        {
            var context = Mock.Create<HttpContextBase>();
            var request = Mock.Create<HttpRequestBase>();
            var response = Mock.Create<HttpResponseBase>();
            var session = Mock.Create<HttpSessionStateBase>();
            var server = Mock.Create<HttpServerUtilityBase>();

            Mock.Arrange(() => request.AppRelativeCurrentExecutionFilePath).Returns("/");
            Mock.Arrange(() => request.ApplicationPath).Returns("/");
            Mock.Arrange(() => request.IsAuthenticated).Returns(true);


            Mock.Arrange(() => response.ApplyAppPathModifier(Arg.IsAny<string>())).Returns<string>(s => s);
            Mock.ArrangeSet(() => response.StatusCode = (int) System.Net.HttpStatusCode.OK);


            Mock.Arrange(() => context.Request).Returns(request);
            Mock.Arrange(() => context.Response).Returns(response);
            Mock.Arrange(() => context.Session).Returns(session);
            Mock.Arrange(() => context.Server).Returns(server);

            return context;
        }

        public static HttpContextBase MockHttpContext(string url)
        {
            var context = MockHttpContext();
            context.Request.SetupRequestUrl(url);
            return context;
        }


        #endregion
        public static void SetMockControllerContext(this Controller controller,
            HttpContextBase httpContext = null,
            RouteData routeData = null,
            RouteCollection routes = null)
        {
            routeData = routeData ?? new RouteData();
            routes = routes ?? RouteTable.Routes;
            httpContext = httpContext ?? MockHttpContext();

            var requestContext = new RequestContext(httpContext, routeData);

            var user = new QmostIdentitySerializeModel()
            {
                UserId = 20,
                SecurityToken = new Guid("4223017F-E6F2-4829-A37F-51C42CF1A04C")
            };
            var qmostIdentity = new QmostIdentity("jonathan", user, new QmostWorkflowsSerializeModel());
            var principal = Mock.Create<IPrincipal>();
            Mock.Arrange(() => principal.Identity).Returns(qmostIdentity);

            var context = new ControllerContext(requestContext, controller);

            Mock.Arrange(() => context.HttpContext.User).Returns(principal);
            controller.ControllerContext = context;
        }

        public static void SetupRequestUrl(this HttpRequestBase request, string url)
        {
            if (url == null)
                throw new ArgumentNullException("url");

            if (!url.StartsWith("~/"))
                throw new ArgumentException("Sorry, we expect a virtual url starting with \"~/\".");

            Mock.Arrange(() => request.QueryString).Returns(GetQueryStringParameters(url));
            Mock.Arrange(() => request.AppRelativeCurrentExecutionFilePath).Returns(GetUrlFileName(url));
            Mock.Arrange(() => request.PathInfo).Returns(string.Empty);
        }

        #region Private

        static string GetUrlFileName(string url)
        {
            return (url.Contains("?"))
                ? url.Substring(0, url.IndexOf("?"))
                : url;
        }

        static NameValueCollection GetQueryStringParameters(string url)
        {
            if (url.Contains("?"))
            {
                var parameters = new NameValueCollection();

                var parts = url.Split("?".ToCharArray());
                var keys = parts[1].Split("&".ToCharArray());

                foreach (var key in keys)
                {
                    var part = key.Split("=".ToCharArray());
                    parameters.Add(part[0], part[1]);
                }

                return parameters;
            }

            return null;
        }

        #endregion
    }
}

1 Answer, 1 is accepted

Sort by
0
Kaloyan
Telerik team
answered on 21 Mar 2016, 12:57 PM
Hi Jonathan,

Thank you for contacting us about this.

In order to fake the UrlHelper.Action call, you will need to Mock the HttpContextBase as well as the HttpWorkerRequest classes, as shown below:
public class HomeControllerTest
{
    UrlHelper Url { get; set; }
    public HomeControllerTest()   
    {
        var routes = new RouteCollection();
        RouteConfig.RegisterRoutes(routes);
  
        var httpContext = Mock.Create<HttpContextBase>();
        Mock.Arrange(() => httpContext.Response.ApplyAppPathModifier(Arg.IsAny<string>()))
            .Returns((string arg) => arg);
  
        Mock.Arrange(() => httpContext.GetService(typeof(HttpWorkerRequest)))
            .Returns(Mock.Create<HttpWorkerRequest>(Behavior.CallOriginal));
        var requestContext = new RequestContext(httpContext, new RouteData());
        Url = new UrlHelper(requestContext, routes);
    }
  
    [TestMethod]
    public void HomePage()
    {
        Assert.AreEqual("/HomeController", Url.Action("Index", "HomeController"));
    }
}

Doing this, you should be able to execute the u.Action("Results", new { id = v.VerificationID }); line and assert on the expectations in your unit test.

I hope this helps.

Regards,
Kaloyan
Telerik
Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Feedback Portal and vote to affect the priority of the items
Tags
General Discussions
Asked by
Jonathan
Top achievements
Rank 1
Answers by
Kaloyan
Telerik team
Share this question
or