Как я подделать/подделать объект сеанса в веб-формах ASP.Net?
Есть ли способ обмануть/подделать объект сеанса в веб-формах ASP.Net при создании модульных тестов?
В настоящее время я сохраняю данные пользователя в переменной сеанса, к которой обращается моя бизнес-логика.
При тестировании моей бизнес-логики изолированно сеанс недоступен. Это, кажется, указывает на плохой дизайн (хотя я не уверен). Должен ли уровень бизнес-логики получать доступ к переменным сеанса в первую очередь?
Если да, то как мне пойти на замену данных пользователя с помощью поддельного объекта для тестирования?
Ответы
Ответ 1
В ASP.NET вы не можете создать тестовое двойное соединение HttpSessionState, потому что оно sealed
. Да, это плохой дизайн со стороны оригинальных дизайнеров ASP.NET, но не так много сделать.
Это одна из многих причин того, почему разработчики TDD и другие SOLID-практики в основном отказались от ASP.NET в пользу ASP.NET MVC и других, более проверяемых фреймворков. В ASP.NET MVC сеанс HTTP моделируется абстрактным классом HttpSessionStateBase.
Вы можете использовать аналогичный подход и позволить своим объектам работать с абстрактным сеансом, а затем обернуть реальный класс HttpSessionState при работе в среде ASP.NET. В зависимости от обстоятельств вы даже можете повторно использовать типы из System.Web.Abstractions, но если нет, вы можете определить свои собственные.
В любом случае ваша бизнес-логика является вашей моделью домена, и она должна быть смоделирована независимо от какой-либо конкретной технологии времени выполнения, поэтому я бы сказал, что она не должна обращаться к объекту сеанса в на первом месте.
Если вам абсолютно необходимо использовать тестовые пары для единиц с участием HttpSessionState, это все равно возможно с некоторыми инвазивными динамическими макетами, такими как TypeMock или Moles, хотя они также имеют множество недостатков (см. это сравнение динамические макеты).
Ответ 2
Вы можете сделать это по существу с четырьмя строками кода. Хотя это не говорит о предыдущем комментарии о переносе сеанса из уровня вашей бизнес-логики, иногда вам может понадобиться сделать это в любом случае, если вы работаете с устаревшим кодом, который сильно связан с сеансом (мой сценарий).
Пространства имен:
using System.Web;
using System.IO;
using System.Web.Hosting;
using System.Web.SessionState;
Код:
HttpWorkerRequest _wr = new SimpleWorkerRequest(
"/dummyWorkerRequest", @"c:\inetpub\wwwroot\dummy",
"default.aspx", null, new StringWriter());
HttpContext.Current = new HttpContext(_wr);
var sessionContainer = new HttpSessionStateContainer(
"id", new SessionStateItemCollection(),
new HttpStaticObjectsCollection(), 10, true,
HttpCookieMode.AutoDetect, SessionStateMode.InProc, false);
SessionStateUtility.AddHttpSessionStateToContext(
HttpContext.Current, sessionContainer);
Затем вы можете обратиться к сеансу без получения ошибки NullReferenceException:
HttpContext.Current.Session.Add("mySessionKey", 1);
Это комбинация кода, скомпилированного из следующих статей:
Ответ 3
Ваши инстинкты правильны - вы не должны получать доступ к частям структуры ASP.NET из своей бизнес-логики. Это будет сеанс.
Чтобы ответить на ваш первый вопрос, вы можете издеваться над статическими классами, используя такой продукт, как Typemock Isolator, но вам будет лучше, если вы реорганизуете свой код для переноса доступа к сеансу в интерфейсе (то есть, IHttpSession.) Затем вы можете mock IHttpSession.
Ответ 4
В веб-формах Asp.Net вы не можете избежать того факта, что ввод фреймворка в ваш код происходит из aspx-страниц. Я согласен с тем, что ваш бизнес-уровень не должен касаться непосредственно компонентов asp.net напрямую, но у вас должен быть контейнер для хранения модели, а сеанс в asp.net - хорошая область. Таким образом, одним из возможных подходов является создание ISessionManager для взаимодействия внутри вашего бизнес-уровня. Затем реализуйте конкретный тип с помощью HttpSessionState... btw, хорошим трюком является использование HttpContext.Current.Session для реализации аксессуаров/получателей из HttpSessionState.
Ваша следующая задача - собрать все вместе.
Ответ 5
Один из подходов состоит в передаче выражения lambda в ваш код, который принимает строку (или какой-либо другой объект) в качестве входных данных и использует ее для установки объекта Session или тестового контейнера.
Однако, как говорили другие, неплохо было бы перевести доступ к объекту Session из вашего BLL.