Статьи

Представляем разработку через тестирование с помощью Rails 3

В продолжение моих предыдущих постов — Создание вашего первого приложения на Rails: модели, представления и контроллеры — я собираюсь рассказать о простом подходе, основанном на тестировании, для добавления новой функции в наше приложение для сокращения URL-адресов, Shorty.

Чтобы протестировать этот процесс, мы сделаем сайт более похожим на реальное сокращение URL-адресов, то есть мы протестируем и реализуем способ генерации простого короткого кода, который представляет сокращаемый URL-адрес.

Сама функциональность относительно проста (в нашем случае мы конвертируем id обратно и вперед между буквенно-цифровым представлением), но это хорошая возможность для применения подхода, основанного на тестировании. Для этого мы будем использовать встроенные средства тестирования Rails, а в конце я также приведу ссылку на еще несколько вариантов для изучения в свое время.

Сегодня мы рассмотрим часть модели, а в следующем посте мы интегрируем наши сокращенные URL-адреса и напишем несколько тестов контроллера.

Что нам нужно

Чтобы это работало, нам нужно реализовать три отдельные вещи:

  • Способ преобразования заданного сохраненного URL в короткий код
  • Способ конвертировать короткий код в сохраненный URL
  • Новый, более короткий маршрут для получения URL с этого.

Приступая к работе, мы хотим открыть существующие тестовые файлы. Когда мы сгенерировали нашу модель URL в первой части, Rails также сгенерировал для нас test/unit/url_test.rb в test/unit/url_test.rb . Открыв его и посмотрев, вы должны увидеть нечто похожее на:

 require 'test_helper' class UrlTest < ActiveSupport::TestCase # Replace this with your real tests. test "the truth" do assert true end end 

Это общая структура модульного теста в Rails 3 — метод test позволяет нам объявлять метод (у нас также есть setup и teardown для поддержки обобщенной среды для наших тестов), и мы используем assert (например, вызов метода assert в код выше). Rails (и Test::Unit , интегрированные в rails инфраструктуры тестирования) поставляются с несколькими утверждениями из коробки, которые мы можем использовать — для списка, посмотрите методы, начинающиеся с assert_ в rails api docs и эту старую assert_ для некоторых из утверждения стандартного тестового блока.

Письменные тесты

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

 test 'creating a url lets us fetch a short code' test 'existing urls have short codes' test 'converting a short code to an id' test 'finding a url from a known short code' test 'finding a url from a invalid short code raises an exception' 

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

 rake test:units 

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

Теперь мы пройдем наши тесты 1 и напишем их. Для начала заполните их по очереди, заменив тестовую заглушку:

 test 'creating a url lets us fetch a short code' do my_url = Url.create(:url => 'http://google.com/') # The url should have a short code assert_present my_url.short_code end test 'existing urls have short codes' do my_url = Url.create(:url => 'http://google.com/') # Force a fetch from the datbase found_url = Url.find(my_url.id) assert_present found_url.short_code assert_equal my_url.short_code, found_url.short_code end test 'finding a url from a known short code' do my_url = Url.create(:url => 'http://google.com/') assert_equal my_url, Url.find_using_short_code!(my_url.short_code) end test 'finding a url from a invalid short code raises an exception' do assert_raises ActiveRecord::RecordNotFound do Url.find_using_short_code! 'non-existant-short-code' end end 

В каждом из тестов мы тестируем некоторые аспекты ожидаемого поведения модели:

  • В нашем первом тесте мы проверяем, что после создания URL-адреса он имеет короткий код, вызывая метод short_code и вызывая assert_present со своим значением.
  • Во втором тесте мы создаем URL-адрес, принудительно перезагружаем его из базы данных (чтобы имитировать его выборку в более поздний момент времени), а затем проверяем, что он также имеет короткий код и, что более важно, тот же самый короткий найденный объект код.
  • В третьем тесте мы создаем URL-адрес и проверяем, что при извлечении его из базы данных (используя наш несуществующий в настоящее время метод find_using_short_code! ) Он будет возвращать тот же URL-адрес.
  • В нашем последнем тесте мы проверяем, что, когда мы даем ему недопустимый короткий код, возникает ожидаемое исключение.

Вернемся к командной строке и снова rake test:units наши тесты с помощью rake test:units , мы все равно должны увидеть 4 ошибки. Это хорошо — это значит, что у нас есть тесты, но мы еще не реализовали их.

Проходя наши тесты

Теперь мы собираемся пройти наши тесты. Для этого нам нужно реализовать два метода. Сначала мы используем short_code экземпляра short_code класса Url а затем find_using_short_code! метод класса.

В url.rb мы добавим метод для генерации короткого кода. На данный момент мы просто будем использовать базовое значение id 36 (например, 10 будет a ):

 class Url < ActiveRecord::Base validates :url, :presence => true def short_code id.to_s 36 end end 

Повторно запустив наши тесты, мы увидим, что 2 из 4 наших тестов теперь пройдены. Далее мы реализуем метод, чтобы найти его по идентификатору, выполнив обратное преобразование (взяв число из базового значения 36):

 class Url < ActiveRecord::Base validates :url, :presence => true def short_code id.to_s 36 end def self.find_using_short_code!(short_code) find short_code.to_i(36) end end 

Запустив наши тесты в последний раз, мы увидим, что все они теперь проходят — теперь мы можем получать и генерировать короткие коды.

Следующие шаги

В следующем посте мы расскажем, как интегрировать наши короткие коды в контроллер и как его протестировать.

На данный момент, посмотрите, можете ли вы написать еще несколько тестов для себя — Один случай, который стоит рассмотреть, это то, что происходит, когда у вас нет идентификатора в модели? (например, он еще не был сохранен).

Внимательные читатели могут также захотеть прочитать о том, как интегрировать RSpec в свое приложение для альтернативного синтаксиса и подхода к написанию тестов. Для дополнительного кредита вы также можете изменить способ конвертации между идентификаторами и короткими кодами, например, вместо использования 36 (от 0 до 9 и от a до b), вы также можете указать разницу между строчными и прописными буквами.