0

I followed code sample in Steve Sanderson's MVC3 book, there is a piece of ControlContext mock code there I can setup form and query string values.

In order to support TryUpdateModel in unit test I made some change to the code, for example I have changed data type of formValues to FormCollection formValues and I added following codes to make it work:

        // form Values values setup
        this.Request.Setup(x => x.Form).Returns(formValues);

        // wire up form with value provider
        if (formValues != null)
        {
            onController.ValueProvider = formValues.ToValueProvider();
        }

Meanwhile I would like to do the same thing to querystring collection, but could not find equivalent class to support such a function.

Who has any idea what shall I do to query string?

2
  • hi - did you find this out? thanks Commented Sep 18, 2012 at 9:59
  • Yes, please see my own answer below. Commented Sep 18, 2012 at 18:37

1 Answer 1

1

Eventually, this is my solution

using System;
using System.Collections.Generic;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using Moq;

/// <summary>
/// A helper class for MVC projects' unit testing.
/// </summary>
public class ContextMocks
{
    /// <summary>
    /// Initializes a new instance of the ContextMocks class.
    /// </summary>
    /// <param name="onController">The controller to mock.</param>
    /// <param name="identityName">The fake security identity name for controller.</param>
    /// <param name="queryStrings">Fake query string values of the Http context.</param>
    /// <param name="formValues">Fake form values of the Http context.</param>
    /// <param name="isNewSession">Enables us to mock if the session was created for the current thread or not.</param>
    public ContextMocks(Controller onController, string identityName, FormCollection queryStrings, FormCollection formValues, bool isNewSession = true)
    {
        this.Cookies = new HttpCookieCollection();

        this.Request = new Mock<HttpRequestBase>();

        this.Response = new Mock<HttpResponseBase>();

        this.Server = new Mock<HttpServerUtilityBase>();

        // Define all the common context objects, plus relationships between them
        this.HttpContext = new Mock<HttpContextBase>();
        this.HttpContext.Setup(x => x.Request).Returns(this.Request.Object);
        this.HttpContext.Setup(x => x.Response).Returns(this.Response.Object);
        this.HttpContext.Setup(x => x.Session).Returns(new FakeSessionState(isNewSession));
        this.HttpContext.Setup(x => x.Application).Returns(new FakeApplicationState());
        this.HttpContext.Setup(x => x.User.Identity.Name).Returns(identityName);
        this.HttpContext.Setup(x => x.Server).Returns(this.Server.Object);

        // cookie setup
        this.Request.Setup(x => x.Cookies).Returns(this.Cookies);
        this.Response.Setup(x => x.Cookies).Returns(this.Cookies);

        // query string setup
        this.Request.Setup(x => x.QueryString).Returns(queryStrings);

        // wire up form with value provider
        if (queryStrings != null)
        {
            onController.ValueProvider = queryStrings.ToValueProvider();
        }

        // form Values values setup
        this.Request.Setup(x => x.Form).Returns(formValues);

        // wire up form with value provider
        if (formValues != null)
        {
            onController.ValueProvider = formValues.ToValueProvider();
        }

        // Apply the mock context to the supplied controller instance
        RequestContext rc = new RequestContext(this.HttpContext.Object, new RouteData());
        onController.ControllerContext = new ControllerContext(rc, onController);
    }

    /// <summary>
    /// Initializes a new instance of the ContextMocks class. By using this constructor the mock will also enable UrlHelper mocking
    /// by using routing table setting.
    /// </summary>
    /// <param name="onController">The controller to mock.</param>
    /// <param name="registerRouteTable">
    /// A delegate to the function to register route table. 
    /// Typically it is MvcApplication.RegisterRoutes function in global.asax.cs.
    /// </param>
    /// <param name="identityName">The fake security identity name for controller.</param>
    /// <param name="queryStrings">Fake query string values of the Http context.</param>
    /// <param name="formValues">Fake form values of the Http context.</param>
    /// <param name="isNewSession">Enables us to mock if the session was created for the current thread or not.</param>
    public ContextMocks(
        Controller onController, 
        Action<RouteCollection> registerRouteTable, 
        string identityName, 
        FormCollection queryStrings, 
        FormCollection formValues,
        bool isNewSession = true)
        : this(onController, identityName, queryStrings, formValues, isNewSession)
    {
        this.Response.Setup(x => x.ApplyAppPathModifier(It.IsAny<string>())).Returns<string>(s => s);

        // Arrange (get the routing config and test context)
        RouteCollection routeConfig = new RouteCollection();
        registerRouteTable(routeConfig);
        onController.Url = new UrlHelper(new RequestContext(this.HttpContext.Object, new RouteData()), routeConfig);
    }

    /// <summary>
    /// Gets Http Context mock.
    /// </summary>
    public Mock<HttpContextBase> HttpContext { get; private set; }

    /// <summary>
    /// Gets Http request mock.
    /// </summary>
    public Mock<HttpRequestBase> Request { get; private set; }

    /// <summary>
    /// Gets Http response mock.
    /// </summary>
    public Mock<HttpResponseBase> Response { get; private set; }

    /// <summary>
    /// Gets the mock server object.
    /// </summary>
    public Mock<HttpServerUtilityBase> Server { get; private set; }

    /// <summary>
    /// Gets Route data.
    /// </summary>
    public RouteData RouteData { get; private set; }

    /// <summary>
    /// Gets or sets A collection used to hold fake cookie values.
    /// </summary>
    private HttpCookieCollection Cookies
    {
        get;
        set;
    }

    /// <summary>
    /// Use queryStringCollectionProvider fake HttpSessionStateBase, because it's hard to mock it with Moq.
    /// </summary>
    private class FakeSessionState : HttpSessionStateBase
    {
        /// <summary>
        /// Enables us to mock whether the session was created for the current thread or not.
        /// </summary>
        private bool isNewSession;

        /// <summary>
        /// Fake session state collection.
        /// </summary>
        private Dictionary<string, object> items = new Dictionary<string, object>();

        /// <summary>
        /// Initializes a new instance of the FakeSessionState class.
        /// </summary>
        /// <param name="isNewSession">Enables us to mock if the session was created for the current thread or not.</param>
        public FakeSessionState(bool isNewSession)
        {
            this.isNewSession = isNewSession;
        }           

        /// <summary>
        /// Gets a value that indicates whether the session was created during the current request.
        /// </summary>
        public override bool IsNewSession
        {
            get
            {
                return this.isNewSession;
            }
        }

        /// <summary>
        /// An indexer to access the fake session item.
        /// </summary>
        /// <param name="name">Name of fake session key.</param>
        /// <returns>Fake session value.</returns>
        public override object this[string name]
        {
            get { return this.items.ContainsKey(name) ? this.items[name] : null; }
            set { this.items[name] = value; }
        }

        /// <summary>
        /// Empties the contents of the session.
        /// </summary>
        public override void Abandon()
        {
            this.items = new Dictionary<string, object>();
        }
    }

    /// <summary>
    /// Use queryStringCollectionProvider fake HttpApplicationStateBase, because it's hard to mock it with Moq.
    /// </summary>
    private class FakeApplicationState : HttpApplicationStateBase
    {
        /// <summary>
        /// Fake application state collection.
        /// </summary>
        private Dictionary<string, object> items = new Dictionary<string, object>();

        /// <summary>
        /// An indexer to access the fake application item.
        /// </summary>
        /// <param name="name">Name of fake application key.</param>
        /// <returns>Fake application value.</returns>
        public override object this[string name]
        {
            get { return this.items.ContainsKey(name) ? this.items[name] : null; }
            set { this.items[name] = value; }
        }

        /// <summary>
        /// Mock out of the lock method.
        /// </summary>
        public override void Lock()
        {
        }

        /// <summary>
        /// Mock out of the unlock method.
        /// </summary>
        public override void UnLock()
        {
        }

        /// <summary>
        /// Adds the fake object to the application object.
        /// </summary>
        /// <param name="name">The key</param>
        /// <param name="value">The value being added in conjunction with the key.</param>
        public override void Add(string name, object value)
        {
            this.items.Add(name, value);
        }
    }
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.