【问题标题】:Difference between HttpContext and HttpContextWrapper in terms of Unit Testing and in terms of Web Forms and MVCHttpContext 和 HttpContextWrapper 在单元测试和 Web 表单和 MVC 方面的区别
【发布时间】:2013-05-27 05:59:28
【问题描述】:

我知道HttpContextHttpContextWrapper 之间的区别如下...

HttpContext

这是老式的 asp.net 上下文。这样做的问题是它没有基类并且不是虚拟的,因此无法用于测试(不能模拟它)。建议不要将其作为函数参数传递,而是传递 HttpContextBase 类型的变量。

HttpContextBase

这是 HttpContext 的(c# 3.5 的新功能)替换。由于它是抽象的,它现在是可模拟的。这个想法是,您希望传递上下文的函数应该期望接收其中之一。具体由HttpContextWrapper实现

HttpContextWrapper

也是 C# 3.5 中的新功能 - 这是 HttpContextBase 的具体实现。要在普通网页中创建其中之一,请使用 new HttpContextWrapper(HttpContext.Current)。

这个想法是,为了使您的代码可单元测试,您将所有变量和函数参数声明为 HttpContextBase 类型,并使用 IOC 框架(例如 Castle Windsor)将其注入。在普通代码中,城堡是注入相当于'new HttpContextWrapper (HttpContext.Current)',而在测试代码中,您将获得 HttpContextBase 的模拟。

但我不知道它的实际用途。我听说与 Web 表单相比,它在单元测试中很有用。但它有什么用呢?


I also know that we can use it to execute the controller and Action as mentioned here

【问题讨论】:

    标签: asp.net-mvc asp.net-mvc-4


    【解决方案1】:

    我听说与 Web 表单相比,它在单元测试中很有用。但是它有什么用呢?

    让我们举一个 ASP.NET MVC 控制器动作的例子,它在响应中添加一个 cookie:

    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            var cookie = new HttpCookie("foo", "bar");
            this.Response.Cookies.Add(cookie);
            return View();
        }
    }
    

    注意那里的 Response 属性。这是一个HttpResponseBase。所以我们可以在单元测试中模拟它:

    public class HttpResponseMock: HttpResponseBase
    {
        private HttpCookieCollection cookies;
        public override HttpCookieCollection Cookies
        {
            get
            {
                if (this.cookies == null)
                {
                    this.cookies = new HttpCookieCollection();
                }
    
                return this.cookies;
            }
        }
    }
    
    public class HttpContextMock: HttpContextBase
    {
        private HttpResponseBase response;
    
        public override HttpResponseBase Response
        {
            get 
            {
                if (this.response == null)
                {
                    this.response = new HttpResponseMock();
                }
                return this.response;
            }
        }
    }
    

    现在我们可以编写单元测试了:

    // arrange
    var sut = new HomeController();
    var httpContext = new HttpContextMock();
    sut.ControllerContext = new ControllerContext(httpContext, new RouteData(), sut);
    
    // act
    var actual = sut.Index();
    
    // assert
    Assert.AreEqual("bar", sut.Response.Cookies["foo"].Value);
    

    由于所有成员都是虚拟的,我们可以使用一个模拟框架,这将避免我们为单元测试编写那些模拟类的需要。例如,NSubstitute 的测试结果如下:

    // arrange
    var sut = new HomeController();
    var context = Substitute.For<HttpContextBase>();
    var response = Substitute.For<HttpResponseBase>();
    var cookies = new HttpCookieCollection();
    context.Response.Returns(response);
    context.Response.Cookies.Returns(cookies);
    sut.ControllerContext = new ControllerContext(context, new RouteData(), sut);
    
    // act
    var actual = sut.Index();
    
    // assert
    Assert.AreEqual("bar", sut.Response.Cookies["foo"].Value);
    

    现在让我们使用一个 WebForm:

    protected void Page_Load(object sender, EventArgs)
    {
        var cookie = new HttpCookie("foo", "bar");
        this.Response.Cookies.Add(cookie);
    }
    

    在这种情况下,Response 属性是具体的HttpResponse。所以你被淘汰了。无法单独进行单元测试。

    【讨论】:

    • 这是否意味着 NVC 具有可以在单元测试项目中调用的操作方法,另一方面,Web 窗体没有方法,而是具有页面加载事件。所以不能直接调用?
    • 不,这意味着 MVC 控制器已经与抽象类(HttpContextBase、HttpResponseBase、HttpRequestBase、...)一起使用,而 WebForm 与具体类(HttpContext、HttpResponse、HttpRequest、...)一起使用。 .)。 ASP.NET MVC 的设计考虑到了这一点,因此框架公开的所有属性和成员都是抽象而不是具体的类。
    • 我检查了httpresponsehttpresponsebase的元数据。两者都具有相同数量的属性和方法。所以它们之间没有区别。对吗?
    • 不,有一个根本的区别:HttpResponseBase 的所有成员都是虚拟的,这意味着你可以模拟它们。 HttpResponse 的成员不是虚拟的,您不能在单元测试中替换它们。没有实际的 ASP.NET,HttpResponse 就无法生存。
    猜你喜欢
    • 2011-04-30
    • 1970-01-01
    • 2013-07-17
    • 2011-02-14
    • 1970-01-01
    • 2012-05-12
    • 1970-01-01
    • 1970-01-01
    • 2020-03-16
    相关资源
    最近更新 更多