Обновление 2013:
Плохая новость заключается в том, что платформа Moles была проектом Microsoft Research (MSR), и не будет поддерживаться в Visual Studio 2012 .Хорошая новость заключается в том, что Microsoft теперь интегрировала проект MSR в основную инфраструктуру как Microsoft Fakes .
Я нашел статью, которая решает вашу проблему, используя вместо нее среду Fakes.Структура Moles:
http://blog.christopheargento.net/2013/02/02/testing-untestable-code-thanks-to-ms-fakes/
Вот обновленная версия моего предыдущего ответа, в которой вместо Moles используется структура Fakes.
using System.Web.Fakes;
// ...
var sessionState = new Dictionary<string, object>();
ShimHttpContext.CurrentGet = () => new ShimHttpContext();
ShimHttpContext.AllInstances.SessionGet = (o) => new ShimHttpSessionState
{
ItemGetString = (key) =>
{
object result = null;
sessionState.TryGetValue(key, out result);
return result;
}
};
Возможно, вы даже сможетесделать так, чтобы это выглядело больше как версия Moles, которую я выложил ранее, хотя я еще не пробовал.Я просто адаптирую код статьи к своему ответу:)
Перед редактированием 2013 года:
Вы сказали, что хотите избежать изменения тестируемого кода.Хотя я думаю, что следует изменить , так как прямой доступ к состоянию сеанса - плохая идея, я могу понять, откуда вы пришли (я был на тесте однажды ...).
Я нашел этот поток, описывающий, как кто-то пытался обойти эту проблему HttpContext
и HttpSessionState
.
Их код в итоге выглядел так:
MHttpContext.CurrentGet = () => new MHttpContext
{
SessionGet = () => new MHttpSessionState
{
ItemGetString = (key) =>
{
if (key == "some")
return "someString"/* or any other object*/;
else return null;
}
}
};
Я бы пошел еще дальше и внедрил бы ItemGetString
со словарем:
var sessionState = new Dictionary<string, object>();
MHttpContext.CurrentGet = // ...
{
// ...
ItemGetString = (key) =>
{
object result = null;
sessionState.TryGetValue(key, out result);
return result;
}
Перед редактированием:
Я обычно решаю такие проблемы, какэто путем инкапсуляции глобального состояния с помощью абстрактного класса или интерфейса, который может быть создан и удален.Затем вместо прямого доступа к глобальному состоянию я внедряю экземпляр моего абстрактного класса или интерфейса в код, который его использует.
Это позволяет мне смоделировать глобальное поведение и делает так, чтобы мои тесты независеть от этого поведения или осуществлять его.
Вот один из способов сделать это (я бы немного поиграл с факторингом):
public interface ISessionContext
{
object this[string propertyName] { get; set; }
}
public class ServerContext : ISessionContext
{
public object this[string propertyName]
{
get { return HttpContext.Current.Session[propertyName]; }
set { HttpContext.Current.Session[propertyName] = value; }
}
}
public class SomeClassThatUsesSessionState
{
private readonly ISessionContext sessionContext;
public SomeClassThatUsesSessionState(ISessionContext sessionContext)
{
this.sessionContext = sessionContext;
}
public void SomeMethodThatUsesSessionState()
{
string somevar = (string)sessionContext["somevar"];
// todo: do something with somevar
}
}
Это потребует изменений в вашем коде.проходит тестирование, но это тип изменений, который хорош как для тестируемости, так и для переносимости кода.