Тестирование функции, которая генерирует ошибку - PullRequest
1 голос
/ 11 августа 2008

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

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

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

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

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

Ответы [ 4 ]

3 голосов
/ 11 августа 2008

Если вы делаете это в .NET, есть атрибут ExpectedException, который вы можете добавить в свой тест:

[Test, ExpectedException(typeof(SpecificException), "Exception's specific message")]
public void TestWhichHasException()
{
    CallMethodThatThrowsSpecificException();
}

Тест пройдет, если будет сгенерировано исключение этого типа и с указанным сообщением. Атрибут имеет другие перегрузки, в том числе наличие InnerExceptions и т. Д.

2 голосов
/ 11 августа 2008

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

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

1 голос
/ 11 августа 2008

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

AFAIK. Обычно при юнит-тестировании имитируют внешние ресурсы для минимизации зависимостей.

0 голосов
/ 18 сентября 2012

Звучит как C ++ для меня. Вам нужен шов для макетирования функций Win32. Например. в вашем классе вы создадите защищенный метод CreateIoCompletionPort(), который вызывает ::CreateIoCompletionPort(), а для вашего теста вы создадите класс, который наследуется от вашего класса порта завершения ввода / вывода и переопределяет CreateIoCompletionPort(), чтобы ничего не делать, кроме как возвращать NULL. Ваш производственный класс по-прежнему ведет себя так, как он был спроектирован, но теперь вы можете имитировать сбой в функции CreateIoCompletionPort().

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

...