Перейти к навигации · Перейти к содержимому

Две книги про тесты

Две последние книги, которые я прочитал, оказались про тесты: «The Art of Unit Testing with Examples in .NET» и «The RSpec Book: Behaviour-Driven Development with RSpec, Cucumber, and Friends». Последовательность прочтения как раз соответствует историческому развитию методологий.

The Art of Unit Testing

Книга «Искусство юнит-тестирования c примерами на .NET» («The Art of Unit Testing with Examples in .NET») посвящена даже не методологии TDD (Test Driven Development) в целом (про это как раз вторая книга), а теме написания правильных тестов. Это важный вопрос сам по себе, ведь тесты можно использовать и без строгого следования принципам TDD (то есть писать тесты не до кода, а после). При этом, плохо написанные тесты могут даже навредить (например, вселяя необоснованную уверенность в коде при рефакторинге).

Очень важно чтобы тесты были читаемыми (как и код), ведь тесты — это еще и документация. Например, не стоит делать в одном тесте более одного assert-а (чтобы не маскировать их при ошибках) или слишком увлекаться DRY (Don't Repeat Yourself), вынося инициализацию объектов из отдельных тестов в общие методы.

Кроме этого, в книге рассматриваются следующие вопросы:

  • Разные способы внедрения зависимостей: Inversion of Control (для конструкторов), Dependency Injection (для свойств), extract and override — их преимущества и недостатки.
  • Поясняется разница между mock (проверяют вызовы и фейлят тесты, вызывая assert) и stub, которые служат лишь «заглушками».
  • Даются советы, вроде того, что не стоит использовать более одного mock в каждом тесте (stub может быть сколько угодно), так как mock-и являются основным предметом проверки каждого теста.
  • Описаны основые «западни», при написании тестов, например, случаи, когда тесты недостаточно хорошо изолированы и зависят от других тестов.
  • Вопросы правильной организации, наименования тестов и прочие полезные приёмы.

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

Тесты уже прочно прижились в инструментарии программистов. Но как и любая другая область написание тестов требует своей культуры. Даже если не следовать в полной мере TDD, тесты писать скорее всего придётся — сейчас для этого созданы все условия (благодаря библиотекам и другим инструментам). А как их лучше писать расскажет данная книга. Уверен, что даже человек с опытом написания тестов сможет найти в ней что-то полезное. ★★★★☆

The RSpec Book

С этой книгой я решил ознакомиться так как в последнее время всё чаще встречаюсь с понятием BDD (Behavior Driven Development) — своего рода, следующей версией TDD. Почти во всех языках программирования это сейчас является трендом: постоянно появляются новые библиотеки и фреймворки в этом стиле, и все большее количество проектов выбирают BDD для написания тестов. Сначала мне было не слишком понятно, чем вообще отличается BDD от TDD. Данная книга как раз ответила на этот вопрос.

Небольшое отступление про TDD/BDD

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

Если следовать традиционному подходу — разработке в стиле «водопад», то сначала пишутся технические задания и спецификации, затем составляются умные диаграммы, а потом пишется код и тесты для него. И весь процесс обычно растягивается на месяцы. Более того, если на последних этапах обнаружены какие-то принципиальные ошибки первых этапов, то стоимость их исправления зачастую становится слишком велика, ведь приходится всё повторять заново.

Agile-методология стала альтернативой традиционному подходу в разработке: вместо большого запланированного каскада используются мини-итерации по реализации фич. Одним из решений по оптимизации процесса разработки стала идея о том, что тесты можно (и нужно) писать до кода, добавляя к ним функцию документирования. Иногда тесты даже рекомендуют называть не тестами, а примерами:

A general rule of thumb is that if the code is hard to use in examples, it’s going to be hard to use everywhere else.

То есть вы не пишете тесты, чтобы проверить, правильно ли работает код, а пишете код, чтобы проверить, правильно ли исполняются функциональные требования в виде тестов. И тесты теперь становятся не просто инструментом для проверки ошибок: теперь они являются формальным документом (протоколом), по которому работает программист. Более того, написание тестов по сути является фазой дизайна — именно в этот момент вы проверяете, насколько ваши API будут удобны в использовании.

Данный подход характерен и для TDD, и для BDD, но последний пошел несколько дальше, меняя формат тестов на более «человеческий». Если TDD-тесты пишутся тестерами (или самими программистами) для программистов, то BDD-тесты пишутся еще и для заказчика. Более того, кроме тестирования юнитов (отдельных объектов), большое внимание уделяется тестированию поведения системы в целом (behavior) — в каком-то смысле это замена интеграционному тестированию и ATDP (Acceptance Test–Driven Planning).

Rspec и Cucumber

Книга рассказывает о двух основных продуктах для BDD-тестирования в мире Ruby: RSpec и Cucumber. Первый отвечает за тестирование объектов (аналог TDD), второй — за описание и тестирование поведения системы (аналог ATDP). Одно из главных отличий от более традиционных методов заключается в упрощении восприятия тестов и спецификаций.

Восприятие упрощается даже из-за использования языка, относящегося не к тестам, а к поведению: Given/When/Then. Спецификации Кукумбера вообще пишутся просто на английском (их можно писать даже на русском). При этом в Кукумбере есть несколько очень интересных фич: например, работа с шаблонами и таблицами подставляемых данных. Тесты RSpec очень похожи на TDD, только вместо assert обычно используется should, а вместо названий методов (типа testEmptyStringShouldBeNil) — строки (it "should return nil with empty string").

Но отличие не только в синтаксисе, а скорее в общем подходе. BDD-подход был разработан как ответ на запросы программистов, которые не знали с чего начать в TDD. Предполагается, что разработка должна проходить в виде цикла:

Сначала вы пишете спецификацию в Кукумбере, затем опускаетесь на уровень реализации и пишете тесты RSpec (понятно, что ни те, ни другие тесты сначала не проходят). Затем вы пишете код, подгоняя его под тесты, пока они не начинают исполняться без ошибок. После этого вы возвращаетесь на уровень программы в целом — к Кукумберу — и пишете новые тесты-спецификации.

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

Читая книгу, вы одновременно делаете упражнение по написанию маленькой игры, заключающейся в угадывании случайных цифр. Советую параллельно с чтением действительно писать код, так как «прорабатывание» его в уме не даёт полного эффекта погружения в процесс.

Все примеры в книге даны на Ruby, но это не мешает тем, кто пишет на других языках. На некоторых платформах тот же Кукумбер можно легко применять для тестирования без изменений синтаксиса (например, для разработки iOS/андроид-приложений есть Calabash), а синтаксис RSpec послужил источником вдохновения для многих библиотек. Например, для JavaScript есть Jasmine, которую использует Angular.js.

В общем, я рекомендую книгу к прочтению: в ней есть и обоснование современных подходов к разработке и конкретный пример следования этим подходам. И даже если вы не будете использовать все описанные подходы в разработке, что-то полезное из них наверняка почерпнёте. ★★★★☆

Ссылки по теме: