asp.net-mvc 带有 HttpContext 的 ASP.NET MVC 单元测试控制器

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2497575/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 00:13:24  来源:igfitidea点击:

ASP.NET MVC unit test controller with HttpContext

asp.net-mvcunit-testing

提问by amurra

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:

我正在尝试为我的一个控制器编写单元测试以验证视图是否正确返回,但该控制器有一个访问 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);
    }

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?

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

采纳答案by Graviton

If you are using Typemock, you can do this:

如果您使用的是Typemock,您可以这样做:

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

回答by Mark Seemann

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

除非你使用 Typemock 或 Moles,否则你不能.

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

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

Here's an example of how you can use Moq to set up a Mock 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

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

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

回答by m1k4

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():

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

回答by pdr

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

对于此类事情,您可能应该使用ActionFilter而不是基类

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

回答by Nate

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

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