More completely mocking the ControllerContext

2 posts, 0 answers
  1. Jonathan
    Jonathan avatar
    2 posts
    Member since:
    Feb 2016

    Posted 16 Mar Link to this post

    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
        }
    }

  2. Kaloyan
    Admin
    Kaloyan avatar
    872 posts

    Posted 21 Mar Link to this post

    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
  3. DevCraft R3 2016 release webinar banner
Back to Top