Pull to refresh

Введение в TDD «на пальцах» (Rails + Rspec)

Ruby on Rails *
Лично для меня, довольно тертого разработчика, процесс внедрения TDD был непростым и местами тернистым.

Вкратце законспектирую, поскольку порог входа в тестирование действительно выше, чем просто сесть и писать код на RoR. Сделаю несколько, как написали бы пиндосы, highlights.
image

Теоретически процесс TDD должен выглядеть так:



1. Написали падающий тест, прогнали rspec, убедились что тест не проходит (красный)

2. Написали кусок кода, прогнали rspec, убедились что тест проходит (зеленый)

3. Отрефакторили, убедились что все хорошо и тесты не падают.

4. Отправили код в продакшн



Тестирование довольно медленно запускается само по себе, поэтому люди делают ухищрения: ставят spork, который держит инстанс приложения в памяти и экономит время при каждом запуске рельс. Уменьшение времени тестов на время запуска (у меня секунд 7-10) гарантировано.
UPDATE: Как подсказали в комментариях (о, слава хабру) имеет смысл обратить внимание на zeus.

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

Раньше тестовые наборы данных хранились в YAML файлах и назывались фикстурами (fixtures). Каждый тест загружал фикстуры из файлов в базу, и, хотя, их можно было загружать выборочно, такая процедура была довольно медленной и ресурсоемкой. Ребята из thoughtbot решили данную проблему тем, что фикстуры стали генерить программно и назвали фабриками (factories). Фабрики действительно ощутимо быстрее и позволяют без проблем создавать связанные ассоциативные инстансы, изменяемые наборы данных (sequence), например, разные emailы пользователей и другие прикольные штуки. Сейчас все еще модно использовать FactoryGirl.

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

например: stackoverflow.com/questions/8303491/how-do-i-make-sure-the-helpers-and-models-reload-in-rspec-when-im-using-spork

Само тестирование



Сейчас модно использовать RSpec, поскольку он лаконичнее и описательнее чем Test::Unit, который идет в комплекте с рельсами. Тесты в rspec называются спеками (от слова спецификация). Вроде само тестирование рельс сейчас тоже переехало на rspec, не знаю. Самый писк моды – приблизиться к человеческому языку, так что бы тесты были как бы метаописаниями, как бы объясняли на примерах как должен работать код. Чем меньше сам текст теста и чем он выразительнее, тем лучше. Мне в этом плане был очень близок cucumber (огурец). Сейчас rspec научился собой заменять cucumber чуть менее чем полностью.

Как сейчас водится, люди тестируют в трех направлениях.

1. Тесты моделей, или юнит-тесты


Здесь мы проверяем корректность методов в моделях, корректность валидаций.

validate_presence_of(:model) не идет в комплекте бойца с rspec, поэтому приходится ставить и подключать shoulda

gem "shoulda-matchers"

и далее в spec_helper.rb

require 'shoulda-matchers'

2. Тесты контроллеров, или как их еще называют, функциональные


Проверяются вещи, что бы create действительно создавал объект или рендерил 'new' и такое прочее

типовой тест будет включать в себя вызов контроллера

post :create, mymodel: param1

и проверку результатов. Например в assigns идет то, что должно присвоиться в методе контроллера

assigns(:mymodel){ should == MyModel.last }

проверяем, что отрендерится темплейт new. Это очевидно, но не интуитивно.

response.should render_template('new')

3. Интеграционные тесты, bdd истории


BDD история это то, как выглядит фича в глазах заказчика в переводе на язык разработчика. Обычно история это одновременно и описание и кусок кода для проведения тестирования этой же фичи.

Это больше парафия Cucumber, однако, rspec в базовой установке тоже создает spec/request/ папку, куда и помещаются интеграционные тесты.

Мне очень нравится подход Cucumber тем, что происходит осмысление «зачем нужна эта фича» при каждом взгляде на тест, поскольку там собственно и написано «зачем». Но мы же знаем, что фичу можно сделать разными способами, главное, чтобы «зачем» осталось тем же самым.

Так вот, интеграционный тест прогоняет цепочку действий при помощи эмуляции браузера.

Чаще всего что бы работала такая хрень подключаются gem capybara или webrat, которые собственно и делают эмуляцию браузера

Тестирование обычно выглядит так:

  • заполнить поле 1 данными 1
  • нажать княпу сабмит
  • проверить, что на странице появились записи с данными 1

примерно такой код

visit services_path

page.should have_content("Сервис антивирусных")


visit и have_content нам достается из гема капибары.

Немного про то, что и как тестировать. Следует проверять пограничные случаи, например, если код должен создавать юзера, то проверьте это двумя тестами:

1. Юзер создается корректно, проверяем что в базке запись появилась.

2. Что мы действительно получаем ошибку, если юзер не создается корректно.

Все, кто уже тестируют, молодцы, а всем, кто еще этого не делает, рекомендую начать.
Tags:
Hubs:
Total votes 38: ↑28 and ↓10 +18
Views 44K
Comments 9
Comments Comments 9