Подтвердить что ты не робот

Разница между HttpContext и HttpContextWrapper в терминах модульного тестирования и с точки зрения веб-форм и MVC

Я знаю, что разница между HttpContext и HttpContextWrapper ниже...

HttpContext

Это винтажный контекст asp.net. Проблема заключается в том, что он не имеет базового класса и не является виртуальным и, следовательно, неприменим для тестирования (не может его издеваться). Он рекомендовал не передавать его в качестве аргументов функции, а вместо этого передавать переменные типа HttpContextBase.

HttpContextBase

Это замена (new to С# 3.5) для HttpContext. Так как он абстрактный, он теперь макет. Идея заключается в том, что ваши функции, ожидающие передачи контекста, должны ожидать получить один из них. Он конкретно реализован HttpContextWrapper

HttpContextWrapper

Также новый в С# 3.5 - это конкретная реализация HttpContextBase. Чтобы создать одну из них на обычной веб-странице, используйте новый HttpContextWrapper (HttpContext.Current).

Идея состоит в том, что для проверки работоспособности вашего кода вы объявляете все свои переменные и функциональные параметры типа HttpContextBase и используете инфраструктуру IOC, например Castle Windsor, для ее ввода. В нормальном коде замок должен ввести эквивалент "нового HttpContextWrapper (HttpContext.Current) ', в то время как в тестовом коде вам будет дано макет HttpContextBase.

Но я не знаю о его реальном использовании. Я слышал, что он полезен в Unit Testing по сравнению с Web Forms. но как это полезно?


Я также знаю, что мы можем использовать его для выполнения контроллера и действия, как указано здесь

4b9b3361

Ответ 1

Я слышал, что это полезно в Unit Testing по сравнению с Web Forms. но как это полезно?

Возьмем пример действия контроллера 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. Это a HttpResponseBase. Поэтому мы можем издеваться над ним в unit test:

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

и теперь мы могли бы написать unit test:

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

И так как все участники виртуальны, мы могли бы использовать насмешливую структуру, которая бы не требовала написать эти макетные классы для unit test. Например, 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. Итак, вы разорены. Невозможно unit test изолировать.