Я надеюсь, что этот вопрос дает некоторые интересные ответы, потому что это тот, который раздражал меня некоторое время.
Есть ли реальная ценность в модульном тестировании контроллера в ASP.NET MVC?
Под этим я подразумеваю, что большую часть времени (и я не гений), мои методы контроллеров, даже в их самом сложном, примерно такие:
public ActionResult Create(MyModel model)
{
// start error list
var errors = new List<string>();
// check model state based on data annotations
if(ModelState.IsValid)
{
// call a service method
if(this._myService.CreateNew(model, Request.UserHostAddress, ref errors))
{
// all is well, data is saved,
// so tell the user they are brilliant
return View("_Success");
}
}
// add errors to model state
errors.ForEach(e => ModelState.AddModelError("", e));
// return view
return View(model);
}
Большая часть тяжелой работы выполняется либо конвейером MVC, либо моей сервисной библиотекой.
Так что, возможно, вопросы могут быть:
- Какова будет ценность модульного тестирования этого метода?
- это не сломалось бы
Request.UserHostAddress
иModelState
с NullReferenceException? Должен ли я пытаться издеваться над этим? - если бы я рефракторил этот метод в многократно используемый «помощник» (что мне, вероятно, следовало бы, учитывая, сколько раз я делаю это!), было бы полезным тестирование, даже если все, что я действительно проверяю, это в основном «конвейер», который, по-видимому, был проверен с точностью до дюйма его жизни Microsoft?
Я думаю , что моя точка действительно есть, делая следующее кажется совершенно бессмысленной и неправильной
[TestMethod]
public void Test_Home_Index()
{
var controller = new HomeController();
var expected = "Index";
var actual = ((ViewResult)controller.Index()).ViewName;
Assert.AreEqual(expected, actual);
}
Очевидно, я туплю с этим преувеличенно бессмысленным примером, но есть ли у кого-нибудь еще мудрость, чтобы добавить сюда?
С нетерпением жду этого ... Спасибо.
c#
unit-testing
asp.net-mvc
LiverpoolsNumber9
источник
источник
Ответы:
Даже для чего-то такого простого, юнит-тест будет служить нескольким целям
Для этого конкретного действия я бы проверил следующее
Вы указали проверку Request и Model для NullReferenceException, и я думаю, что ModelState.IsValid позаботится об обработке NullReference для Model.
Запечатывание запроса позволяет вам защититься от нулевого запроса, который, как я думаю, вообще невозможен в производстве, но может произойти в модульном тесте. В интеграционном тесте это позволило бы вам предоставить различные значения UserHostAddress (запрос все еще является пользовательским вводом, если речь идет об элементе управления, и его следует соответствующим образом протестировать)
источник
Мои контроллеры тоже очень маленькие. Большая часть «логики» в контроллерах обрабатывается с использованием атрибутов фильтра (встроенных и рукописных). Так что мой контроллер обычно имеет только несколько заданий:
ActionResult
Большая часть привязки модели выполняется автоматически ASP.NET MVC. DataAnnotations обрабатывают большую часть проверки для меня тоже.
Даже с таким небольшим количеством тестов, я все еще обычно пишу их. По сути, я проверяю, что мои репозитории вызываются и что
ActionResult
возвращается правильный тип. У меня есть удобный метод для того,ViewResult
чтобы убедиться, что верный путь просмотра возвращен, и модель представления выглядит так, как я ожидаю. У меня есть другой для проверки правильного контроллера / действие установлено дляRedirectToActionResult
. У меня есть другие тестыJsonResult
и т. Д.К сожалению, результатом подкласса
Controller
класса является то, что он предоставляет множество удобных методов, которые используютHttpContext
внутренне. Это затрудняет юнит-тестирование контроллера. По этой причине я обычно помещаюHttpContext
-зависимые вызовы за интерфейсом и передаю этот интерфейс конструктору контроллера (я использую веб-расширение Ninject для создания своих контроллеров для меня). Обычно в этом интерфейсе я использую вспомогательные свойства для доступа к сеансу, настройкам конфигурации, IPrinciple и помощникам URL.Это требует должной осмотрительности, но, думаю, оно того стоит.
источник
BaseControllerTests
класс, где они все живут. Я копирую свои репозитории. Я подключаю их с помощью Ninject.ActionResult
s, чтобы проверить переданные URL, модели и т. Д.Очевидно, что некоторые контроллеры намного сложнее, но основаны исключительно на вашем примере:
Что произойдет, если myService выдает исключение?
Как примечание стороны.
Кроме того, я бы поставил под сомнение целесообразность передачи списка по ссылке (это необязательно, поскольку c # в любом случае проходит по ссылке, но даже если это не так) - передавая действие errorAction (Action), которое служба затем может использовать для передачи сообщений об ошибках в который затем может быть обработан так, как вы хотите (может быть, вы хотите добавить его в список, может быть, вы хотите добавить ошибку модели, может быть, вы хотите зарегистрировать ее).
В вашем примере:
вместо ошибок ref, например, do (string s) => ModelState.AddModelError ("", s).
источник