| Понедельник, 11 февраля, 2013
Метки: ASP.NET Web API Комментарии: 0
Тестирование – важная часть разработки каждого сервиса. Это проверка того, что сервис работает, как и запланировано. В данной статье мы покажем вам основные способы тестирования ASP.NET Web API, также рассмотрим преимущества и недостатки каждого вида тестирования для более эффективной проверки работы сервисов.
Тестирование ASP.NET Web API можно разделить на три основных категории:
Это самый простой способ тестирования сервисов WEB API. Вы создаете экземпляр контроллера и затем вызываете его action-методы с нужными параметрами. В итоге проверим метод, выполнил ли он свою задачу, например, изменил ли он данные в базе и возвратил ли нужный результат.
В качестве примера рассмотрим такой тест сервиса WEB API. Допустим, у нас есть метод возвращающий фильм по ID. Сигнатура метода может быть такой.
public class MoviesController : ApiController { public Movie GetMovie(int id); }
И предположим следующий сценарий. Если ID фильма есть в нашей базе данных, мы получаем соответствующий объект фильма. Но если фильм с заданным ID не найден, метод должен вернуть стандартный код ответа HTTP - 404 Not Found. Пример для такого теста может выглядеть так:
public void GetMovie_ThrowsNotFound_WhenMovieNotFound() { var controller = new MoviesController(); HttpResponseException responseException = Assert.Throws(() => controller.GetMovie(-1)); Assert.Equal(HttpStatusCode.NotFound, responseException.Response.StatusCode); }
Главный принцип - объем теста должен быть минимальным и как можно проще.
Модульное тестирование контроллеров – это хорошо, но в нем есть свои недостатки.
Во первых, контроллер Web API может зависеть от объекта Request или свойств конфигурации, которые нужны для правильной работы action-методов. Такие методы, как Request.CreateResponse работают хорошо для обычного сетевого соединения к Web API. Но они не будут работать в модульных тестах, пока не будут сконфигурированы дополнительные настройки.
Во-вторых модульное тестирование контроллеров не покрывает, все что может потенциально выдавать ошибки. Если вы используете собственные реализации обработчиков HTTP-данных (custom message handler), маршрутизацию, фильтры, параметры связывания, форматтеры, то модульное тестирование тут не поможет. И даже, если вы это все не используете, запрос по какой то причине может просто не выполнить метод или метод вернет неправильные параметры.
В третьих модульное тестирование не всегда помогает предположить, какой будет HTTP ответ. Например, необходимо чтобы бы был прописан нужный HTTP-заголовок в ответе сервера или сервер должен вернуть нужный код ответа HTTP. Если метод возвращает HttpResponseMessage или выдает исключение HttpResponseException, как в примере выше, тогда надо иметь возможность получить и проверить ответ от сервера. Иначе не будет полного контроля над тем, какой ответ сервера в действительности получит клиент.
В таких случаях имеет смысл настроить внутренний HttpServer, и посылать ему запросы для тестов. Вы получаете ответы от такого сервера и проверяете их. Одним из преимуществ такой архитектуры Web API является то, что вы можете тестировать сервер без сетевого подключения. Вы имитируете процесс отправки запросов, получаете ответы от сервера, как от реально действующего рабочего сервера.
Ниже то же самый тест, но написанный к in-memory серверу:
[Fact] public void GetMovie_ReturnsNotFound_WhenMovieNotFound() { HttpConfiguration config = new HttpConfiguration(); config.Routes.MapHttpRoute("Default", "{controller}/{id}"); HttpServer server = new HttpServer(config); using (HttpMessageInvoker client = new HttpMessageInvoker(server)) { using (HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, "http://localhost/Movies/-1")) using (HttpResponseMessage response = client.SendAsync(request, CancellationToken.None).Result) { Assert.Equal(HttpStatusCode.NotFound, response.StatusCode); } } }
Для проверки ответа сервера можно использовать следующий код:
ObjectContent content = Assert.IsType(response.Content); Assert.Equal(expectedValue, content.Value); Assert.Equal(expectedFormatter, content.Formatter);
И заключительный способ тестирования WEB API – это запустить рабочий сервер, настроить порт прослушки и отсылать ему запросы. Это будет выглядеть так:
[Fact] public void GetMovie_ReturnsNotFound_WhenMovieNotFound() { HttpSelfHostConfiguration config = new HttpSelfHostConfiguration("http://localhost/"); config.Routes.MapHttpRoute("Default", "{controller}/{id}"); using (HttpSelfHostServer server = new HttpSelfHostServer(config)) using (HttpClient client = new HttpClient()) { server.OpenAsync().Wait(); using (HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, "http://localhost/Movies/-1")) { Assert.Equal(HttpStatusCode.NotFound, response.StatusCode); } server.CloseAsync().Wait(); } }
Для проверки ответа можно написать так:
Assert.Equal(expectedResponseBody, response.Content.ReadAsStringAsync().Result);
Но если это возможно, вы должны избегать написания тестов к реальному серверу. Web API сервис так теcтировать нецелесообразно. Данным способом вы можете тестировать нечто большее – например клиента, сетевой стек операционной системы, то есть тестировать хост вашего сервиса. Если вы тестируете больше, чем это необходимо, вы можете спровоцировать проблемы на других участках и превратить поддержку тестирования и отладки в настоящий кошмар.
Однако есть и случаи подходящие для тестирования рабочего сервера. Например, нужно проверить могут ли клиент и сервер обмениваться сообщениями. Лучше тестировать клиента и сервера раздельно. Можно проверить посылает ли клиент запрос так как надо, и затем проверить возвращает ли сервер нужный ответ. Также хостинг имеет существенное значение, когда нужно удостовериться, что клиент правильно выполняет запросы к Web API. Допустим, используются криптографические протоколы SSL/TLS и нужно проверить, что соединение работает. Пишем один тест к рабочему серверу, если есть контакт, то остальные тесты уже пишем модульно или к внутреннему серверу для проверки корректной работы сервиса Web API.
Copyright © CodeHint.ru 2013-2024 (v2.4.7 - работает на Angular Universal)Калькулятор инвест-портфеля