Mock HttpContext с использованием moq для unit test

Мне нужен макет HttpContext для модульного тестирования. Но я борюсь с этим.

Я делаю метод, который меняет sessionId программным путем с помощью SessionIdManager. И SessionIdManager требует HttpContext, а не HttpContextBase.

Но я не мог найти никакого примера, чтобы сделать издевательство над HttpContext. Все примеры только для создания HttpContextBase.

Я пробовал ниже, но они не работали

HttpContext httpContext = Mock<HttpContext>();
HttpContext httpContext = (HttpContext)GetMockHttpContextBase();

public HttpContextBase GetMockHttpContextBase()
{
   var context = new Mock<HttpContextBase>();
   var request = new Mock<HttpRequestBase>();
   var response = new Mock<HttpResponseBase>();
   var session = new Mock<HttpSessionStateBase>();
   var application = new Mock<HttpApplication>();
   var httpContext = new Mock<HttpContext>();
   var server = new Mock<HttpServerUtilityBase>();
   var user = new Mock<IPrincipal>();
   var identity = new Mock<IIdentity>();
   var urlHelper = new Mock<UrlHelper>();
   var routes = new RouteCollection();
   var requestContext = new Mock<RequestContext>();

   requestContext.Setup(x => x.HttpContext).Returns(context.Object);
   context.Setup(ctx => ctx.Request).Returns(request.Object);
   context.Setup(ctx => ctx.Response).Returns(response.Object);
   context.Setup(ctx => ctx.Session).Returns(session.Object);
   application.Setup(x => x.Context).Returns(httpContext.Object);
   context.Setup(ctx => ctx.ApplicationInstance).Returns(application.Object);
   context.Setup(ctx => ctx.Server).Returns(server.Object);
   context.Setup(ctx => ctx.User).Returns(user.Object);
   user.Setup(ctx => ctx.Identity).Returns(identity.Object);
   identity.Setup(id => id.IsAuthenticated).Returns(true);
   identity.Setup(id => id.Name).Returns("test");
   request.Setup(req => req.Url).Returns(new Uri("http://tempuri.org"));
   request.Setup(req => req.RequestContext).Returns(requestContext.Object);
   requestContext.Setup(x => x.RouteData).Returns(new RouteData());
   request.SetupGet(req => req.Headers).Returns(new NameValueCollection());

   return context.Object;
}

Есть ли способ сделать mock из HttpContext или использовать HttpContextBase для HttpContext?

Пожалуйста, помогите мне.

Ответ 1

Это общий вопрос здесь, и корень проблемы - НЕ ТРЕБОВАТЬ ТИПЫ, ВЫ НЕ СОБСТВЕННЫ. Вместо сложного издевательства, чтобы попытаться воспроизвести поведение класса, который вы не пишете (что означает, что вы догадываетесь о том, что он делает и что вам нужно для фальсификации), введите абстракцию между вашим кодом и внешним объектом HttpContext и mock это абстракция. Как говорит один из пионеров макетных объектов:

Ключ для меня был, когда Джо Уолнс придумал радикальное понятие "Не издевайтесь над типами, которыми вы не владеете". Это означает: прекратить прыгать через обручи для работы с закрытыми библиотеками, используйте тесты для обнаружения ваши объекты и то, что они говорят друг другу.

http://higherorderlogic.com/2004/02/the-big-idea-is-messaging/

Ответ 2

Если вы настроились на издевку HttpContext, вам придется использовать довольно много шаблонов, чтобы имитировать его.

Phil Haack подробно описывает этот подход в этом блоге: http://haacked.com/archive/2005/06/11/simulating_httpcontext.aspx/

Как я уже говорил, мне хотелось, чтобы "легкий" способ протестировал этот метод. Не было бы проблем, если HttpContext.Current был допустимым экземпляром HttpContext. К счастью, статическое свойство Current HttpContext читается и записывается. Все, что требуется, - установить это свойство в правильно созданный экземпляр HttpContext. Однако создание этого экземпляра не так просто, как моя первая попытка. Я избавлю вас от скучных деталей и просто покажу вам, в чем я оказался.

Он предоставляет схему симулятора здесь: http://haacked.com/archive/2007/06/19/unit-tests-web-code-without-a-web-server-using-httpsimulator.aspx/

Имейте в виду, что вы, вероятно, решаете на интеграционное тестирование со всем этим, поскольку логика, связанная с имитацией этих объектов, является нетривиальной и может мешать надежности ваших тестов.