Как лучше всего протестировать функцию, которая выдает ошибку? Или тестировать функцию, которая достаточно устойчива к сбоям?
Например; У меня есть класс I/O Completion Port, который вызывает конструктор, если он не может правильно инициализировать порт. Это использует функцию Win32 из CreateIoCompletionPort в списке инициализаторов. Если дескриптор установлен неправильно - ненулевое значение - конструктор выдаст исключение. Я никогда не видел, чтобы эта функция выходила из строя.
Я почти уверен, что эта (и другие функции, подобные ей в моем коде), если они потерпят неудачу, будут вести себя правильно, код составляет 50 строк, включая пробелы, поэтому мои вопросы
а) стоит ли тестировать что выкинет
б) а если стоит потестить, то как?
c) следует ли тестировать простые классы-оболочки, поскольку они являются модульными?
Для б) я подумал о том, чтобы переопределить CreateIoCompletionPort и передать значения. В модульном тесте переопределите его и заставьте его возвращать 0 при передаче определенного значения. Однако, поскольку это используется в конструкторе, оно должно быть статическим. Это кажется верным или нет?





Определенно стоит протестировать условия сбоя, так как ваш класс правильно генерирует исключение, когда вы этого хотите, и чтобы исключения правильно обрабатывались в классе.
Это легко сделать, если вы воздействуете на объект, переданный конструктору ... просто передайте имитацию. В противном случае я предпочитаю, чтобы функциональность была перемещена в защищенный метод и переопределила защищенный метод, чтобы вызвать мой случай отказа. Я буду использовать Java в качестве примера, но перенести идеи на C# должно быть достаточно:
public class MyClass {
public MyClass() throws MyClassException {
// Whatever, including a call to invokeCreateIoCompletionPort
}
protected int invokeCreateIoCompletionPort(String str, int i) {
return StaticClass.createIoCompletionPort(str, i);
}
}
public class MyTest {
public void myTest() {
try {
new MyClass();
fail("MyClassException was not thrown!");
} catch (MyClassException e) {
}
}
private static class MyClassWrapper extends MyClass {
@Override
protected int invokeCreateIoCompletionPort(String str, int i) {
throw new ExpectedException();
}
}
}
Как видите, довольно легко проверить, генерируется ли исключение конструктором или методом, который вы тестируете, а также довольно легко внедрить исключение из внешнего класса, который может вызвать исключение. Извините, я не использую ваш реальный метод, я просто использовал это имя, чтобы проиллюстрировать, как оно звучит так, как будто вы его используете, и как я буду тестировать случаи, которые, по его мнению, вы хотите протестировать.
По сути, любые детали API, которые вы предоставляете, обычно можно протестировать, и если вы хотите ЗНАТЬ, что исключительные случаи работают должным образом, вы, вероятно, захотите проверить это.
Вам следует подумать о написании кода таким образом, чтобы можно было имитировать порт завершения ввода-вывода. Создайте интерфейс / абстрактный класс, который предоставляет необходимые вам методы для объекта ввода-вывода, а также напишите и протестируйте реализацию, которая делает вещи так, как предполагалось (и, возможно, с возможностью имитации сбоя).
AFAIK - это обычная практика для имитации внешних ресурсов при модульном тестировании, чтобы минимизировать зависимости.
Если вы делаете это в .NET, есть атрибут ExpectedException, который вы можете добавить в свой тест:
[Test, ExpectedException(typeof(SpecificException), "Exception's specific message")]
public void TestWhichHasException()
{
CallMethodThatThrowsSpecificException();
}
Тест будет пройден, если выброшено исключение этого типа и с указанным сообщением. Атрибут имеет другие перегрузки, включая InnerExceptions и т. д.
Для меня это звучит как C++. Вам нужен шов, чтобы имитировать функции Win32. Например. в своем классе вы должны создать защищенный метод CreateIoCompletionPort(), который вызывает ::CreateIoCompletionPort(), а для своего теста вы создаете класс, который является производным от вашего класса порта завершения ввода-вывода и переопределяет CreateIoCompletionPort(), чтобы ничего не делать, кроме как вернуть NULL. Ваш производственный класс по-прежнему ведет себя так, как был разработан, но теперь вы можете смоделировать сбой в функции CreateIoCompletionPort().
Этот метод взят из книги Майкла Фезерса «Эффективная работа с устаревшим кодом».