开发者

ASP.NET MVC unit test controller with HttpContext

开发者 https://www.devze.com 2022-12-24 07:38 出处:网络
I am trying to write a unit test for my one controller to verify if a view was returned properly, but this controller has a basecontroller that accesses the HttpContext.Current.Session.Everytime I cre

I am trying to write a unit test for my one controller to verify if a view was returned properly, but this controller has a basecontroller that accesses the HttpContext.Current.Session. Everytime I create a new instance of my controller is calls开发者_高级运维 the basecontroller constructor and the test fails with a null pointer exception on the HttpContext.Current.Session. Here is the code:

public class BaseController : Controller
{       
    protected BaseController()
    {
       ViewData["UserID"] = HttpContext.Current.Session["UserID"];   
    }
}

public class IndexController : BaseController
{
    public ActionResult Index()
    {
        return View("Index.aspx");
    }
}

    [TestMethod]
    public void Retrieve_IndexTest()
    {
        // Arrange
        const string expectedViewName = "Index";

        IndexController controller = new IndexController();

        // Act
        var result = controller.Index() as ViewResult;

        // Assert
        Assert.IsNotNull(result, "Should have returned a ViewResult");
        Assert.AreEqual(expectedViewName, result.ViewName, "View name should have been {0}", expectedViewName);
    }

Any ideas on how to mock (using Moq) the Session that is accessed in the base controller so the test in the descendant controller will run?


Unless you use Typemock or Moles, you can't.

In ASP.NET MVC you are not supposed to be using HttpContext.Current. Change your base class to use ControllerBase.ControllerContext - it has a HttpContext property that exposes the testable HttpContextBase class.

Here's an example of how you can use Moq to set up a Mock HttpContextBase:

var httpCtxStub = new Mock<HttpContextBase>();

var controllerCtx = new ControllerContext();
controllerCtx.HttpContext = httpCtxStub.Object;

sut.ControllerContext = controllerCtx;

// Exercise and verify the sut

where sut represents the System Under Test (SUT), i.e. the Controller you wish to test.


If you are using Typemock, you can do this:

Isolate.WhenCalled(()=>controller.HttpContext.Current.Session["UserID"])
.WillReturn("your id");

The test code will look like:

[TestMethod]
public void Retrieve_IndexTest()
{
    // Arrange
    const string expectedViewName = "Index";

    IndexController controller = new IndexController();
    Isolate.WhenCalled(()=>controller.HttpContext.Current.Session["UserID"])
    .WillReturn("your id");
    // Act
    var result = controller.Index() as ViewResult;

    // Assert
    Assert.IsNotNull(result, "Should have returned a ViewResult");
    Assert.AreEqual(expectedViewName, result.ViewName, "View name should have been {0}", expectedViewName);
}


Snippet:

var request = new SimpleWorkerRequest("/dummy", @"c:\inetpub\wwwroot\dummy", "dummy.html", null, new StringWriter());
var context = new HttpContext(request);
SessionStateUtility.AddHttpSessionStateToContext(context, new TestSession());
HttpContext.Current = context;

Implementation of TestSession():

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.SessionState;

namespace m1k4.Framework.Test
{
    public class TestSession : IHttpSessionState
    {
        private Dictionary<string, object> state = new Dictionary<string, object>();

        #region IHttpSessionState Members

        public void Abandon()
        {
            throw new NotImplementedException();
        }

        public void Add(string name, object value)
        {
            this.state.Add(name, value);
        }

        public void Clear()
        {
            throw new NotImplementedException();
        }

        public int CodePage
        {
            get
            {
                throw new NotImplementedException();
            }
            set
            {
                throw new NotImplementedException();
            }
        }

        public System.Web.HttpCookieMode CookieMode
        {
            get
            {
                throw new NotImplementedException();
            }
        }

        public void CopyTo(Array array, int index)
        {
            throw new NotImplementedException();
        }

        public int Count
        {
            get
            {
                throw new NotImplementedException();
            }
        }

        public System.Collections.IEnumerator GetEnumerator()
        {
            throw new NotImplementedException();
        }

        public bool IsCookieless
        {
            get
            {
                throw new NotImplementedException();
            }
        }

        public bool IsNewSession
        {
            get
            {
                throw new NotImplementedException();
            }
        }

        public bool IsReadOnly
        {
            get
            {
                throw new NotImplementedException();
            }
        }

        public bool IsSynchronized
        {
            get
            {
                throw new NotImplementedException();
            }
        }

        public System.Collections.Specialized.NameObjectCollectionBase.KeysCollection Keys
        {
            get
            {
                throw new NotImplementedException();
            }
        }

        public int LCID
        {
            get
            {
                throw new NotImplementedException();
            }
            set
            {
                throw new NotImplementedException();
            }
        }

        public SessionStateMode Mode
        {
            get
            {
                throw new NotImplementedException();
            }
        }

        public void Remove(string name)
        {
            this.state.Remove(name);
        }

        public void RemoveAll()
        {
            this.state = new Dictionary<string, object>();
        }

        public void RemoveAt(int index)
        {
            throw new NotImplementedException();
        }

        public string SessionID
        {
            get
            {
                return "Test Session";
            }
        }

        public System.Web.HttpStaticObjectsCollection StaticObjects
        {
            get
            {
                throw new NotImplementedException();
            }
        }

        public object SyncRoot
        {
            get
            {
                throw new NotImplementedException();
            }
        }

        public int Timeout
        {
            get
            {
                return 10;
            }
            set
            {
                throw new NotImplementedException();
            }
        }

        public object this[int index]
        {
            get
            {
                throw new NotImplementedException();
            }
            set
            {
                throw new NotImplementedException();
            }
        }

        public object this[string name]
        {
            get
            {
                return this.state[name];
            }
            set
            {
                this.state[name] = value;
            }
        }

        #endregion
    }
}


You should probably use an ActionFilter instead of a base class for this sort of thing

[UserIdBind]
public class IndexController : Controller
{
    public ActionResult Index()
    {
        return View("Index.aspx");
    }
}


I'd checkout the ASP.NET-MVC book listed here -- toward the end, there is a good section on Mocking framewors -- http://www.hanselman.com/blog/FreeASPNETMVCEBookNerdDinnercomWalkthrough.aspx

0

精彩评论

暂无评论...
验证码 换一张
取 消