带有HttpContext的ASP.NET MVC单元测试控制器

时间:2010-03-23 04:27:03

标签: asp.net-mvc unit-testing

我正在尝试为我的一个控制器编写一个单元测试来验证视图是否正确返回,但是这个控制器有一个访问HttpContext.Current.Session的基本控制器。每次我创建一个我的控制器的新实例都会调用basecontroller构造函数,并且测试失败并在HttpContext.Current.Session上出现空指针异常。这是代码:

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

关于如何模拟(使用Moq)在基本控制器中访问的Session的任何想法,以便后代控制器中的测试将运行?

5 个答案:

答案 0 :(得分:64)

除非您使用Typemock或Moles,you can't

在ASP.NET MVC中,您不应该使用HttpContext.Current。将您的基类更改为使用ControllerBase.ControllerContext - 它具有HttpContext属性,可以公开可测试的HttpContextBase类。

以下是如何使用Moq设置Mock HttpContextBase的示例:

var httpCtxStub = new Mock<HttpContextBase>();

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

sut.ControllerContext = controllerCtx;

// Exercise and verify the sut

其中sut表示被测系统(SUT),即您要测试的控制器。

答案 1 :(得分:5)

如果您使用Typemock,则可以执行此操作:

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

测试代码如下:

[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);
}

答案 2 :(得分:3)

你应该使用ActionFilter代替基类来进行此类事情

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

答案 3 :(得分:3)

摘录:

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;

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

答案 4 :(得分:1)

我会查看这里列出的ASP.NET-MVC书籍 - 最后,关于Mocking framewors有一个很好的部分 - http://www.hanselman.com/blog/FreeASPNETMVCEBookNerdDinnercomWalkthrough.aspx