// codeart.ru / Вопрос/Ответ / Немного о behavior тестировании в TDD Форум

Немного о behavior тестировании в TDD rss подписка

Автор: Evgeniy Sergeev

Я уже немного размышлял на тему state-based testing, сейчас хочу попытаться рассказать о своем понимании behaviour-based testing (тестирование поведения). Должен отметить, что после того как я понял, что тестирование бывает двух типов (тестирование состояний и тестирование поведения), строить тесты стало намного проще. И чуть ниже я расскажу почему.

Behaviour-base testing — это такое тестирование, в основе которого лежит не проверка значений переменных, а проверка того, что все необходимые методы вызваны нужное количество раз. При этом проверка логики работы самого метода в расчет не берется. Очень важно отметить, что «тестирование поведения», как правило, делается через Stub-ы (прим. Mock — это имитация объета, Stub — это заглушка для функции).

Почему нельзя без Stub-ов? Все дело в том, что в ООП есть такое понятие как инкапсуляция — сокрытие данных и кода внутри объекта. Благодаря этому свойству разработчик имеет возможность в будущем изменять внутреннее устройство объекта, не изменяя при этом код, использующий данный объект (программирование в соответствии с интерфейсом, а не реализацией).

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

Насколько я понимаю, лагерь TDD разработчиков поделен на две части: те, которые работают только с использованием Mock-ов или Stub-ов, и те, которые стараются их не использовать вообще (классический подход). Так как использовать Behaviour-based testing без Stub-ов затруднительно, то в соответствии с классическим взглядом данный метод тестирования должен использоваться как можно реже. Но в некоторых ситуациях применение state-based testing сопряжено с большим количеством неудобств.

Я имею ввиду то, что составные объекты могут включать в себя много других объектов, которые зависят друг от друга по времени жизни. Таким образом, состояние исходного объекта строится на основе состояния всех используемых объектов. Если все объекты были ранее протестированы по отдельности, то проверять их состояние — это повторять уже существующие тесты. Гораздо проще предположить, что все внутренние объекты работают как надо, и задача программиста сводится к тому, чтобы проверить были ли вызваны все необходимые методы этих объектов. Т.е. по сути выполнить Behaviour-based test.

Например, очень удобно использовать Behaviour-based test для проверки работы контроллеров в рамках MVC архитектуры. Ведь по сути контроллер не содержит никаких собственных данных, вместо этого он изменяет состояние модели. Конечно, можно написать тест, который будет проверять работу контроллера по состоянию модели — если после вызова необходимых методов контроллера модель находится в нужном состоянии, то все ок. Но на практике это просто неудобно. Особенно если ранее модель тестировалась отдельно. Намного проще в данном случае использовать Behaviour-based test.

Пара слов о недостатках этого подхода. Основной недостаток в том, что заменяя реальный объект на фиктивный, мы ухудшаем качество тестирования. Теоретически возможна такая ситуация, когда все объекты в композиции по отдельности работают нормально, а в совокупности нет. Но у меня есть сильное подозрение, что при таком раскладе и state-based testing может не дать положительных результатов.

Наиболее простой пример, при котором тестирование частей может проходить успешно, а тестирование композиции проваливаться — это когда тестируемые объекты для определения своего состояния используют глобальные переменные. Тогда коллизия может возникнуть, если один объект самовольно изменит состояние глобальной переменной, а другой объект будет уверен, что переменная не менялась. В таком случае state-based testing способно выявить проблему в работе объектов. Но даже при таком раскладе нельзя быть уверенным, что все объекты, способные изменить состояние глобальной переменной, попали в тест. То есть по сути защититься от коллизий при использовании глобальных переменных трудно в любом случае.

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

P.S. Я запустил очередное обсуждение — Какой метод тестирования предпочтительнее предлагаю всем желающим высказать свое мнение.

  1. Немного про State тестирование в TDD
  1. Отличная статья, спасибо.
    От себя могу привести пример из своей практики когда тестирование состояния я просто не мог сделать. Мне нужно было написать тест к методу который по случайному возвращал объекты из БД.

Leave a Reply

« »