Я только что начал изучать ASP.NET MVC. При сравнении ASP.NET MVC с Веб-формами одному из основного преимущества MVC всегда говорят быть лучшей поддержкой Поблочного тестирования. Могу я получил хорошее объяснение того, как оно имеет лучшую поддержку?
Редактирование: Если возможный обеспечьте пример в обоих.
Asp.Net MVC имеет лучшую поддержку модульного тестирования по одной основной причине - вся архитектура построена на использовании HttpContextBase
, HttpRequestBase
и HttpResponseBase
.
Asp.Net webforms зависит от HttpContext.Current
, который является синглтоном, над которым у вас нет контроля - он устанавливается и передается вашим страницам как часть HttpApplication
, выполняющего запрос. В большинстве случаев, чтобы страница выполнялась правильно, необходимо выполнить ее в реальном HttpContext
. Поскольку многие свойства HttpContext не настраиваются (например, Request и Response), очень трудно сконструировать поддельные запросы для отправки объектам страницы.
Это превращает модульное тестирование страниц веб-форм в кошмар, поскольку все ваши тесты будут нуждаться во всевозможных настройках контекста.
В отличие от ASP.Net MVC, где вы можете подделать HttpContext! Теперь вашему коду даже не нужен веб-сервер для создания контекста, вы можете просто установить нужные вам биты и передать сымитированный контекст вашему методу.
Гораздо более громоздко тестировать код за страницей, чем тестировать контроллер. В паттерне MVC существует более логичное разделение логики представления, что облегчает написание тестов.
Поскольку вы можете создать объект контроллера в вашем модульном тесте, вызвать некоторые действия на нем и сразу же увидеть результат, то вы можете Assert.IsBlahBlahBlah();
на нем.
Например,
[TestMethod]
public void Index()
{
// Arrange
HomeController controller = new HomeController();
// Act
ViewResult result = controller.Index() as ViewResult;
Assert.IsNotNull(result);
}
с помощью этого метода вы теперь знаете, что ваше представление Index возвращается из контроллера Home.
Жизненный цикл страницы ASP.NET делает невероятно сложным модульное тестирование классов, производных от Page
, который начинает со слишком большого количества обязанностей и становится божественным объектом, когда вы добавляете к нему логику приложения. Что еще хуже, он имеет скрытые зависимости от статических классов и требует конструктора по умолчанию без параметров, что ограничивает ваши возможности по внедрению зависимостей.
Поэтому, чтобы сделать страницу ASP.NET WebForms тестируемой, вам нужно вынести всю логику из ваших code-behinds и поместить ее в другой класс - обычно Presenter, как в Model-View-Presenter паттерне.
Контроллеры ASP.NET MVC уже отделены от своих шаблонов и не обременены жизненным циклом страницы ASP.NET.
Если вы хотите использовать ASP.Net WebForms ( как я) и модульные тесты вместе, взгляните на это:
У меня работает.
Вы можете сделать точно то же самое с Web Forms, просто люди, которые не знают лучше, пишут код, который нельзя протестировать таким образом.
Нет причин располагать бизнес-логику в классе codebehind. То же самое с логикой доступа к данным. Даже здесь это позволяет вам тестировать части приложения, наиболее подверженные как ошибкам, так и тестированию.
Кто-то может сказать, что это не позволяет вам тестировать нажатия кнопок и другие события пользовательского интерфейса. Если вы хотите это сделать, тогда вы можете пойти дальше и создать свой собственный MVC или MVP или другой подобный паттерн, который действительно использует отдельный интерфейс для действий пользовательского интерфейса. Затем проведите точно такой же тест, как и при использовании ASP.NET MVC.
И у вас все еще остается проблема невозможности тестирования кода на стороне клиента.
Немного ОТ, но вы можете захотеть посмотреть на веб-страницы Selenium для модульного тестирования....
В отношении предложения Лоуренса о селене существует также WatiN .
Это не относится к MVC, но я думаю, что MVC определенно помогает в том, что он сохраняет идентификаторы элементов и классы чистыми и упрощает выборку из теста.
С помощью WatiN вы можете делать следующее (пример с их сайта).
[Test]
public void SearchForWatiNOnGoogle()
{
using (var browser = new IE("http://www.google.com"))
{
browser.TextField(Find.ByName("q")).TypeText("WatiN");
browser.Button(Find.ByName("btnG")).Click();
Assert.IsTrue(browser.ContainsText("WatiN"));
}
}