Эффективные юнит тесты. Часть I.
Простой способ сократить число юнит тестов и сохранить 100% покрытие кода – разбить тесты на элементарные случаи и перебрать все комбинации. Этот способ хорошо подходит для тестирования отдельных функций и методов.
Возьмем для примера функцию OpenHandle:
HANDLE OpenThread( DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwThreadId );
Результат этой функции зависит как от значения каждого из переданных параметров, так и от внешних условий, например от контекста безопасности (security context) процесса и DACL открываемого потока.
Можно выделить следующие элементарные тесты:
- Запрашиваемая маска доступа (dwDesiredAccess):
- Корректная комбинация флагов;
- Запрещенная комбинация флагов. Например, один из резервных битов установлен в единицу;
- Флаг, разрешающий наследование описателя порожденным процессом (bInheritHandle):
- TRUE;
- FALSE;
- Идентификатор потока (dwThreadId):
- Собственного потока;
- Существующего потока;
- Несуществующего потока;
- Потока, который уже завершился;
- Потока, принадлежащему другому процессу;
- Контекст безопасности потока, в котором вызывается OpenHandle:
- Имеющий полный доступ к открываемому потоку;
- Имеющий частичный доступ к открываемому потоку;
- Не имеющий доступ к открываемому потоку;
- И так далее:
Теперь осталось лишь реализовать алгоритм перебора тестов таким образом, чтобы каждая комбинация тестов включала только один тест из каждой категории. Каждой полученной комбинации тестов будет соответствовать один вызов OpenHandle с уникальным набором параметров, включая неявные параметры, такие как состояние внешних по отношению к функции объектов.
Преимущества такого подхода очевидны:
- Перебор всех вариантов дает хорошее покрытие, приближающееся к 100%;
- Каждый из элементарных тестов очень прост в реализации;
- Набор тестов легко расширяется;
- Легко задать ожидаемый результат каждой комбинации тестов: успешно/неуспешно. Достаточно лишь задать ожидаемый результат для каждого элементарного теста и сложить их используя <Логическое И>.
Не обошлось и без недостатков, главный из которых, – в большинстве случаев не нужно перебирать все разрешенные комбинации параметров. Типичная функция имеет меньше ветвлений, чем количество всех комбинаций. Тем не менее, при таком подходе изменения в тестируемом коде не потребуют новых тестов при условии, что количество параметров не изменилось.
На этом пока все. Пример реализации такого алгоритма будет в следующей части.
Recent Comments