В продолжение моих предыдущих постов — Создание вашего первого приложения на 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), вы также можете указать разницу между строчными и прописными буквами.