Как макетировать 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();
    ...
Другие вопросы по тегам