Как я могу провести модульное тестирование поведения атрибута HandleError для метода контроллера? - PullRequest
7 голосов
/ 22 апреля 2009

Я пытаюсь проверить поведение моего приложения ASP.Net MVC при непредвиденной ошибке. В частности, я пытаюсь убедиться, что пользователь перенаправлен на страницу с ошибкой, которую я определил для своего приложения. Проблема, с которой я сталкиваюсь, заключается в том, что я не могу проверить поведение метода контроллера, как ожидалось.

Для моих обычных тестов поведения я создаю объект фиктивного бизнес-правила и передаю его контроллеру, а затем проверяю ViewResult из метода контроллера, который я хочу протестировать. Это прекрасно работает для моих целей, когда все работает как положено. Однако , когда я выкидываю исключение из метода бизнес-правила, исключение передается через результат метода контроллера , а не обрабатывается (метод контроллера имеет атрибут 'HandleError') контроллером, чтобы был возвращен соответствующий ViewResult для моей страницы ошибки.

Есть ли способ проверить поведение атрибута HandleError таким образом? Или я иду по этому поводу совершенно неправильно? Я понимаю, что мог бы использовать Selenium (тестирование в браузере, которое попадало бы на реальный сервер), чтобы проверить поведение в реальном браузере, но насмешливые подобные тесты позволяют мне делать это быстрее и с гораздо меньшими накладными расходами ...

Пример тестового кода:

// WidgetController.Index() makes a call to GetWidgets to retrieve a 
//  List<Widget> instance.

// this works as expected since the appropriate ViewResult is returned 
//  by the controller
public void TestWidgetControllerIndex_NoResultsFound()
{
    var mockBR = new Mock<IBusinessRules> { CallBase = true };
    mockBR.Setup(br=>fr.GetWidgets()).Returns(new List<Widget>());    
    WidgetController controller = new WidgetController(mockBR.Object);
    ViewResult result = (ViewResult)controller.Index();
    Assert.AreEqual("Index", result.ViewName);
    Assert.AreEqual(0, 
        ((WidgetIndexViewData)result.ViewData.Model).Widgets.Count);
}

// this test is unable to reach the assertion statements due to the problem 
//  outlined above. WidgetController.Index has the HandleError attribute 
//  properly applied and the behaviour via the interface is as expected
public void TestWidgetControllerIndex_BusinessRulesExceptionEncountered()
{
    var mockBR = new Mock<IBusinessRules> { CallBase = true };
    mockBR.Setup(br=>fr.GetWidgets()).Throws<ApplicationException>();    
    WidgetController controller = new WidgetController(mockBR.Object);
    ViewResult result = (ViewResult)controller.Index();
    // The ApplicationException thrown by the business rules object bubbles 
    //  up to the test through the line above. I was expecting this to be 
    //  caught and handled by the HandleError filter (which would then let  
    //  me verify the behaviour results via the assertion below)..
    Assert.AreEqual("Error", result.ViewName);
}

Буду признателен за любые предположения относительно того, что я могу делать неправильно или же я просто подхожу к этому с совершенно неправильного направления. Я делаю предположение, что тестирование на уровне метода контроллера является подходящим способом, так как именно здесь применяется атрибут HandleError .. (Если мне нужно протестировать на уровне приложения, возможно ли это сделать с помощью аналогичного инстанцированные объекты вместо использования чего-то вроде Selenium?)

Обновление Я пришел к выводу, что не следует тестировать функциональность, связанную с атрибутом HandleError, в каждом действии контроллера. На самом деле меня не волнует, что он делает, я просто хочу убедиться, что ошибка обработана (с точки зрения моего теста, независимо от того, имеет ли значение его пользовательский код или библиотеки MVC, это функциональность, которую я хочу проверить ).

В итоге я обернул действия моего контроллера в блоки try / catch, чтобы принудительно вернуть представление Error в результате метода (а не атрибут ErrorHandler, перехватывающий ошибку при выходе из метода). ). Таким образом, я могу утверждать в своих модульных тестах, что ошибка правильно обрабатывается с соответствующей обратной связью. Я не очень доволен дополнительной длиной, которую это добавляет к моим методам контроллера, но она позволяет мне предоставить дружественное, конкретное сообщение об ошибке пользователю (я использую метод расширения, чтобы отобразить обратную связь и выполнить регистрацию). (Так что у подхода «попробуй / поймай» есть плюсы и минусы ..)

Я не уверен на 100%, что это самый чистый путь, но он достигает моей цели - иметь возможность проверить, что ошибки обрабатываются с помощью модульных тестов контроллера (быстро), а не выполнять тесты в браузере. (медленный). В общем, пока это достаточно , пока я не найду более чистого решения. Я решил предложить вознаграждение, если кто-то сталкивается с подобной проблемой и нашел лучшее решение.

Ответы [ 2 ]

7 голосов
/ 23 апреля 2009

Я думаю, что вы не можете проверить это. И вы не хотите. Вы можете проверить, что ожидаемое исключение выдается методом контроллера. Используя отражение, вы можете проверить, что у действия или контроллера есть атрибут, который вы ожидаете, и что у атрибута есть определенные ожидаемые значения свойств. Однако работа по перехвату исключения и выполнению атрибута - это поведение платформы, а не ваш код. Вообще говоря, вы не должны тестировать код, который не принадлежит вам (фреймворк).

1 голос
/ 30 апреля 2009

Да, я согласен с Тимом. То, что вы описываете, является интеграционным тестом. Поведение HandleErrorAttribute зависит от базового поведения ASP.NET, например, от того, включены или выключены пользовательские ошибки в web.config.

Для вашего модульного теста вы можете просто использовать отражение, чтобы убедиться, что атрибут присутствует.
У команды MVC есть модульные тесты для HandleErrorAttribute, поэтому вам не нужно их писать. :) Затем просто вручную проверьте свои действия, чтобы убедиться, что вы хотите именно такого поведения. Пока вы никогда не меняете / не удаляете атрибут, поведение не должно меняться.

Если вы хотите автоматизировать интеграционный тест, вы можете использовать Watin или Selenium для автоматизации фактического запроса браузера, чтобы убедиться, что поведение вашего приложения не меняется.

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