Как получить и установить заголовки http в действии, способ тестирования - PullRequest
4 голосов
/ 18 сентября 2009

У меня есть действие, которое возвращает либо FileContentResult, либо NotModifiedResult, который является пользовательским типом результата, который возвращает HTTP 304, чтобы указать, что запрошенный ресурс не был изменен, например:

[ReplaceMissingPicture(Picture = "~/Content/Images/nothumbnail.png", MimeType = "image/png")]
public ActionResult Thumbnail(int id)
{
    var item = Service.GetItem(id);

    var requestTag = Request.Headers["If-None-Match"] ?? string.Empty;
    var tag = Convert.ToBase64String(item.Version.ToArray());

    if (tag == requestTag)
    {
        return new NotModifiedResult();
    }

    if (item.Thumbnail != null)
    {
        var thumbnail = item.Thumbnail.ToArray();
        var mime = item.PictureMime;

        Response.AppendHeader("ETag", tag);

        return File(thumbnail, mime);
    }
    else
    {
        return null;
    }
}

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

Что бы решить эту проблему?

К вашему сведению, фильтр ReplaceMissingPicture возвращает конкретный ресурс в случае, если в результате этого действия был возвращен ноль, чтобы не вызвать вызов MapPath () из контроллера по той же причине.

Ответы [ 2 ]

1 голос
/ 20 сентября 2009

Как насчет создания подкласса FileResult - скажем, ETagFileResult - который в своем методе ExecuteResult() устанавливает заголовок ETag, а затем по умолчанию реализует базовый класс? Вы можете протестировать этот класс с поддельным контекстом (как вы, вероятно, с вашим NotModifiedResult), чтобы убедиться, что он делает правильные вещи. И убрать всю сложность из тестирования контроллера.

Если это не так, возможно установить поддельный контекст на контроллере в вашем тесте (после создания экземпляра класса перед вызовом метода действия). См., Например, этот вопрос . Но это похоже на большую работу.

(Кстати, похоже, вы там дважды цитируете значение тега: один раз, когда установлен tag, и еще раз, когда вы фактически установите заголовок ....)

1 голос
/ 18 сентября 2009

Первым шагом будет создание интерфейса, который упрощает необходимые вам услуги: -

  public interface IHeaders
  {
       public string GetRequestHeader(string headerName);
       public void AppendResponseHeader(string headerName, string headerValue);
  }

Теперь создайте реализацию по умолчанию: -

 public Headers : IHeaders
 {
       public string GetRequestHeader(string headerName)
       {
            return HttpContext.Current.Request[headerName];
       }
       public void AppendResponseHeader(string headerName, string headerValue)
       {
            HttpContext.Current.Response.AppendHeader(headerName, headerValue);
       } 
 }

Теперь добавьте новое поле в свой контроллер: -

     private IHeaders myHeadersService;

добавить новый конструктор в свой контроллер: -

     public MyController(IHeaders headersService) 
     {
         myHeadersService = headersService;
     }

изменить или добавить конструктор по умолчанию: -

    public MyController()
    {
         myHeadersService = new Headers();
    }

теперь в вашем коде действия используйте myHeadersService вместо объектов Response и Request.

В ваших тестах создайте собственную реализацию интерфейса IHeaders для эмуляции / тестирования кода Action и передачи этой реализации при создании контроллера.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...