Таймауты

Код, который содержит циклы или рекурсию, может, при определённых условиях, исполняться бесконечно долго.

Ещё встречается код, который должен выполняться фиксированное время. Хороший пример такого кода — генерация виджета персональных новостей на крупном сайте. Он должен выполниться за определённое время, скажем 10 миллисекунд. Соответственно, он должен за указанное время либо вернуть персонализированные новости, либо вернуть какой-либо ответ по умолчанию.

Разумеется, при написании такого кода хочется написать тест, проверяющий это поведение: бесконечные рекурсии и ответ за указанное время. Последнее, правда, больше относится к интеграционным тестам.

Подготовка

Возьмём пустой maven проект и добавим к нему JUnit:

Простой таймаут

Сегодня мы будем решать уравнения методом бисекции. Уравнение я выбрал погромоздкее, с некрасивыми коэффициентами и каким-то неровным решением: http://www.wolframalpha.com/input/?i=%281%2Fe%5E%28x*ln2.81%29%29%2B7.34sqrt%28x%29-12.6%2B2.9845sin%28x%29

Код решения тоже прост и незатейлив — прямолинейная реализация метода половинного деления:

И тест очень и очень простой:

Но, если с точностью 0.01 требуется всего несколько шагов итерации, то при 0.0000001 шагов будет уже больше и вычисление займёт ощутимое время (миллисекунду, ага):

Этот тест провалится, если поиск корня уравнения займёт более одной миллисекунды.

Таймауты и правила

Таймаут можно задавать не только для одного теста, но и для всего класса в целом с помощью правил. Допустим, я хочу убедится, что несколько корней вышеописанного уравнения находятся одинаково быстро:

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

Код примера доступен на github.