Home > itblogs > Эффективные юнит тесты. Часть I.

Эффективные юнит тесты. Часть I.

August 6th, 2006

Простой способ сократить число юнит тестов и сохранить 100% покрытие кода – разбить тесты на элементарные случаи и перебрать все комбинации. Этот способ хорошо подходит для тестирования отдельных функций и методов.

Возьмем для примера функцию OpenHandle:

HANDLE
OpenThread(
    DWORD dwDesiredAccess,
    BOOL bInheritHandle,
    DWORD dwThreadId
    );

Результат этой функции зависит как от значения каждого из переданных параметров, так и от внешних условий, например от контекста безопасности (security context) процесса и DACL открываемого потока.

Можно выделить следующие элементарные тесты:

  • Запрашиваемая маска доступа (dwDesiredAccess):
    • Корректная комбинация флагов;
    • Запрещенная комбинация флагов. Например, один из резервных битов установлен в единицу;
  • Флаг, разрешающий наследование описателя порожденным процессом (bInheritHandle):
    • TRUE;
    • FALSE;
  • Идентификатор потока (dwThreadId):
    • Собственного потока;
    • Существующего потока;
    • Несуществующего потока;
    • Потока, который уже завершился;
    • Потока, принадлежащему другому процессу;
  • Контекст безопасности потока, в котором вызывается OpenHandle:
    • Имеющий полный доступ к открываемому потоку;
    • Имеющий частичный доступ к открываемому потоку;
    • Не имеющий доступ к открываемому потоку;
  • И так далее:

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

Преимущества такого подхода очевидны:

  • Перебор всех вариантов дает хорошее покрытие, приближающееся к 100%;
  • Каждый из элементарных тестов очень прост в реализации;
  • Набор тестов легко расширяется;
  • Легко задать ожидаемый результат каждой комбинации тестов: успешно/неуспешно. Достаточно лишь задать ожидаемый результат для каждого элементарного теста и сложить их используя <Логическое И>.

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

На этом пока все. Пример реализации такого алгоритма будет в следующей части.

Comments are closed.