Как макетировать httpcontext в сервисе
Как можно смоделировать httpcontext в этом сервисе?
Когда я пытаюсь выполнить модульное тестирование этого сервиса, он жалуется на нулевой httpcontext.
Что можно использовать вместо httpcontext? Я использую веб-формы не MVC. Я видел несколько сообщений о фальсификации класса httpcontext, но без использования веб-форм.
public class FileService : IFileService
{
public string GetEmployeePicLocation(Employee employee)
{
string AgentFilesDirectory = "~\\AgentFiles\\";
Image newImage = new Image();
DirectoryInfo diSubPath =
new DirectoryInfo(HttpContext.Current.Server
.MapPath(AgentFilesDirectory + employee.User_Name));
string localDIR = AgentFilesDirectory + employee.User_Name + "\\";
string defaultDIR = AgentFilesDirectory + "nopic\\nopic.jpg";
string strFile;
if (diSubPath.Exists)
{
FileInfo[] arrJPG = diSubPath.GetFiles("*.jpg");
FileInfo[] arrPNG = diSubPath.GetFiles("*.png");
if (!(arrJPG.Length == 0) || !(arrPNG.Length == 0))
{
foreach (FileInfo f in diSubPath.GetFiles("*.jpg"))
{
newImage.ImageUrl = localDIR + employee.PicFile;
}
foreach (FileInfo f in diSubPath.GetFiles("*.png"))
{
newImage.ImageUrl = localDIR + employee.PicFile;
}
}
else
{
newImage.ImageUrl = defaultDIR;
}
}
if (!(diSubPath.Exists))
{
newImage.ImageUrl = defaultDIR;
}
return newImage.ImageUrl.ToString();
}
}
4 ответа
Даже если вы не используете MVC, HttpContextBase определен в сборке System.Web (или, если вы используете.Net 3.5, в System.Web.Abstractions), и вы все равно можете его использовать. Измените ваш класс на экземпляр HttpContextBase, и вы можете создать макет и настроить его по мере необходимости.
Ваш класс будет выглядеть так:
public class FileService : IFileService
{
private HttpContextBase httpContext;
public FileService(HttpContextBase httpContext) {
this.httpContext = httpContext;
}
Тогда в вашем тесте:
var httpContextMock = new Mock<HttpContextBase>();
httpContextMock.Setup(x => x.SkipAuthorization).Returns(true);
var fileService = new FileService(httpContextMock.Object);
Вам также понадобится использовать некоторый шаблон DI, чтобы экземпляр HttpContextBase передавался либо в вашем конструкторе, либо посредством внедрения свойства.
Я думаю, что вам придется делать нечто подобное для ваших вызовов различных классов System.IO, если только у вас нет места в настройке файловой системы и вы не готовы к тестам.
Я хотел бы использовать IoC и ввести некоторые свойства интерфейса, которые обеспечат доступ для выбора свойств HttpContext. При тестировании вы просто используете свою реализацию, которая будет снабжать метод необходимыми значениями во время теста.
вот некоторый псевдо-код:
public class FileService : IFileService
{
// injected property
public IHttpContext CurrentContex {get;set;}
public string GetEmployeePicLocation(Employee employee)
{
string AgentFilesDirectory = "~\\AgentFiles\\";
Image newImage = new Image();
DirectoryInfo diSubPath = new DirectoryInfo(CurrentContex.Server.MapPath(AgentFilesDirectory + employee.User_Name));
// ...
}
}
PS: я думаю, что вы ищете заглушку HttpContext. Пожалуйста, посмотрите здесь http://martinfowler.com/articles/mocksArentStubs.html
В качестве альтернативы используйте HostingEnvironment.MapPath . .it не нуждается в httpcontext . .avoid httpcontext
Я вижу, что вы получили ответы на некоторые вопросы о том, как имитировать это, просто подумал, что я бы предложил альтернативный метод, который может быть проще, когда требуются усилия для замены статического доступа;
Если вы переместите доступ к HttpContext
виртуальному методу;
protected virtual DirectoryInfo GetEmployeeDirInfo(Employee employee)
{
return new DirectoryInfo(
HttpContext.Current.Server.MapPath(AgentFilesDirectory + employee.User_Name));
}
и замените старую строку, делающую доступ;
DirectoryInfo diSubPath = GetEmployeeDirInfo(employee);
... вы можете внезапно тривиально заменить доступ, "насмехаясь" над классом вручную;
internal class FileServiceMock : FileService
{
protected override DirectoryInfo GetEmployeeDirInfo(Employee employee)
{
return new DirectoryInfo("C:\\Temp");
}
}
... и просто протестируйте FileServiceMock в своем тесте.
void Testmethod() {
FileService service = new FileServiceMock();
...