Как упомянуто выше, использование статического ErrorDisplay вызывает ряд проблем с тестированием, а внедрение в реализации IErrorDisplay решит некоторые из них, но не все (см. MessageBox ниже).Однако ...
Static + Interface
Если вам нужно сохранить статический класс ErrorDisplay и не хотите использовать Shell для TypeMock, вы можете добавить уровень косвенности
public interface IDisplayErrorImplementation {
void ShowErrorMessage(string message, Exception ex);
}
public class DefaultDisplayErrorImplementation : IDisplayErrorImplementation {
public void ShowErrorMessage(string message, Exception ex) {
//...
}
}
public static class DisplayError {
static DisplayError(){
Implementation = new DefaultDisplayErrorImplementation();
}
public static IDisplayErrorImplementation Implementation { get; set;}
public static void ShowErrorMessage(string message, Exception ex) {
Implementation.ShowErrorMessage(message, ex);
}
}
Вы можете сохранить существующие вызовы ErrorDisplay, но теперь они более заменяемы и тестируемы.
Это не идеальное решение, но, если поддерживать унаследованный код, оно позволяет добавить некоторую тестируемость без необходимостисделать серьезную переделку.
MessageBox
У вас есть другая проблема с запуском модульных тестов на ErrorDisplay;у вас появится MessageBox.Не хорошо, если вы пытаетесь запустить тесты в тестовом жгуте (или как часть сборки).
Опять косвенность - твой друг.Вы можете заменить вызов MessageBox.Show () на вызов MessageDisplayService.Show ().Реализация по умолчанию может вызывать окно сообщения, а фиктивное может использоваться для тестирования (либо фиктивная, либо простая реализация ничего не делать)
Юнит тестирование
Каковы границы юнитов для тестирования?
Из вопроса видно, что вы хотите запустить тест для MyClass :: MyMethod (), вызвать IOException и увидеть, что GetIODisplayMessage () вызывается.Если я неправильно понял, пропустите следующий раздел:)
Планируете ли вы делать это для каждого класса / метода, где может возникнуть IOException?Планируете ли вы делать это для каждого класса / метода, где могут возникать все другие типы исключений, обрабатываемые ErrorDisplay?
Это большая работа, для которой просто снова и снова повторяется тестирование кода ErrorDisplay.
Границы, которые я вижу:
MyClass :: MyMethod
Если возникает исключение, оно вызывает ErrorDisplay.ShowErrorMessage (), передавая "MyMethod"и исключение.
Все, что после этого находится вне его контроля и не должно быть частью модульных тестов.
ErrorDisplay.ShowErrorMessage ()
Если он вызывается с IOException, то он показывает сообщение, которое он получает, вызывая GetIODisplayMessage ().
Это не зависит (как написано выше) от вызывающего кода и может быть проверено модулем отдельно.
ErrorDisplay.GetIODisplayMessage ()
Возвращает правильное сообщение об ошибке.Хорошо, немного излишне, если значение жестко закодировано, но показывает принцип.
При тестировании MyClass :: MyMethod мы хотим убедиться, что при возникновении исключения вызывается код отображения ошибки, передавая правильное имя метода и исключение.
При тестировании ErrorDisplay.ShowErrorMessage (), мы проверяем, что получаем правильное сообщение для типа исключения, который мы вызываем MessageDisplayService.Show () с именем метода + ":" + <> нам не нужно тестировать здесь текст IODisplayMessage.
При тестировании ErrorDisplay.GetIODisplayMessage () мы проверяем, что оно возвращает правильное сообщение.
Надеюсь, это полезно,
Alan.