Как модульное тестирование лучше в ASP.NET MVC, чем в веб-формах?

Я только начал изучать ASP.NET MVC. При сравнении ASP.NET MVC с веб-формами одно из главных преимуществ MVC всегда считается лучшей поддержкой Unit Testing. Могу ли я получить хорошее объяснение того, как он лучше поддерживает?

Изменить: Если возможно, укажите пример в обоих.

Ответы

Ответ 1

Asp.Net MVC имеет лучшую поддержку модульного тестирования по одной основной причине - вся архитектура построена для использования HttpContextBase, HttpRequestBase и HttpResponseBase.

Веб-формы Asp.Net зависят от HttpContext.Current, который является единственным элементом, который вы не контролируете - он настроен и передан на ваши страницы как часть HttpApplication, выполняющего запрос. В большинстве случаев для правильной работы страницы необходимо выполнить ее в реальном HttpContext. Поскольку многие свойства HttpContext не устанавливаются (например, Request and Response), очень сложно создавать поддельные запросы для отправки на ваши объекты страницы.

Это делает блок тестирования страниц веб-страниц кошмаром, поскольку он соединяет все ваши тесты с необходимостью всех видов настройки контекста.

Сравните это с ASP.Net MVC, где вы можете издеваться над HttpContext! Теперь вашему коду даже не нужен веб-сервер, чтобы дать ему контекст, вы можете просто настроить нужные вам биты и передать подмеченный контекст вашему методу.

Ответ 2

Жизненный цикл страницы ASP.NET делает невероятно трудным для unit test классов, которые происходят из Page, который начинается со слишком большого числа и становится объектом божественным объектом, когда вы добавляете к нему логику приложения. Хуже того, он имеет скрытые зависимости от статических классов и требует конструктора без параметров по умолчанию, который ограничивает вашу способность устанавливать зависимости.

Итак, чтобы сделать страницу ASP.NET WebForms пригодной для проверки, вам нужно извлечь всю логику из ваших кодовых задержек и поместить ее в другой класс - обычно Presenter, как в Модель-View-Presenter.

Контроллеры ASP.NET MVC уже отделены от своих шаблонов и не обременены жизненным циклом страницы ASP.NET.

Ответ 3

Поскольку вы можете создать объект контроллера в своем unit test, вызовите на него некоторые действия и сразу увидите результат, затем вы можете Assert.IsBlahBlahBlah(); на нем.

Например,

    [TestMethod]
    public void Index()
    {
        // Arrange
        HomeController controller = new HomeController();

        // Act
        ViewResult result = controller.Index() as ViewResult;

        Assert.IsNotNull(result);
    }

С помощью этого метода вы теперь знаете, что ваш индексный указатель возвращается с главного контроллера.

Ответ 4

Если вы хотите использовать ASP.Net WebForms (например, я) и модульные тесты вместе, посмотрите на это:

WebForms MVP на codeplex

Работает для меня.

Ответ 5

Намного сложнее проверить код за страницей, чем проверять контроллер. С шаблоном MVC существует более логичное разделение логики представления, что упрощает запись тестов.

Ответ 6

Вы можете сделать то же самое с веб-формами, это просто люди, которые не знают лучше писать код, который не может быть протестирован таким образом.

Нет причин иметь бизнес-логику в классе codebehind. То же самое с логикой доступа к данным. Даже там, где вы можете протестировать те части приложения, которые наиболее подвержены ошибкам и тестированию.

Некоторые могут сказать, что не позволяют вам проверять кнопки и другие события пользовательского интерфейса. Если вы хотите это сделать, вы можете продолжить свой собственный MVC или MVP или другой такой шаблон, который использует отдельный интерфейс для действий пользовательского интерфейса. Затем выполните точно такой же тест, который вы сделали бы, используя ASP.NET MVC.

И у вас все еще есть проблема неспособности протестировать клиентский код.

Ответ 7

Слегка OT, но вы можете посмотреть веб-страницы Selenium для тестирования единиц.

Ответ 8

В отношении предложения Лоуренса о Селене также есть 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"));
 }
}