Тестирование функции, которая вызывает сбой

Как лучше всего протестировать функцию, которая выдает ошибку? Или тестировать функцию, которая достаточно устойчива к сбоям?

Например; У меня есть класс I/O Completion Port, который вызывает конструктор, если он не может правильно инициализировать порт. Это использует функцию Win32 из CreateIoCompletionPort в списке инициализаторов. Если дескриптор установлен неправильно - ненулевое значение - конструктор выдаст исключение. Я никогда не видел, чтобы эта функция выходила из строя.

Я почти уверен, что эта (и другие функции, подобные ей в моем коде), если они потерпят неудачу, будут вести себя правильно, код составляет 50 строк, включая пробелы, поэтому мои вопросы

а) стоит ли тестировать что выкинет
б) а если стоит потестить, то как?
c) следует ли тестировать простые классы-оболочки, поскольку они являются модульными?

Для б) я подумал о том, чтобы переопределить CreateIoCompletionPort и передать значения. В модульном тесте переопределите его и заставьте его возвращать 0 при передаче определенного значения. Однако, поскольку это используется в конструкторе, оно должно быть статическим. Это кажется верным или нет?

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
0
797
4

Ответы 4

Определенно стоит протестировать условия сбоя, так как ваш класс правильно генерирует исключение, когда вы этого хотите, и чтобы исключения правильно обрабатывались в классе.

Это легко сделать, если вы воздействуете на объект, переданный конструктору ... просто передайте имитацию. В противном случае я предпочитаю, чтобы функциональность была перемещена в защищенный метод и переопределила защищенный метод, чтобы вызвать мой случай отказа. Я буду использовать 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().

Этот метод взят из книги Майкла Фезерса «Эффективная работа с устаревшим кодом».

Другие вопросы по теме