Если вы похожи на меня, вы любите писать код. Вы могли бы делать это часами в день каждый день и чувствовать, что живете своей лучшей жизнью, но как насчет написания тестов для вашего кода? Вы просто съежились от одного упоминания об этом? Ничего страшного, если да. Я тоже несколько раз. Мы знаем, что тесты могут сэкономить нам много времени, когда мы вернемся к рефакторингу или добавлению функций, но иногда процесс их написания может показаться очень утомительным. Я здесь, чтобы показать вам, что, по крайней мере, с Ruby on Rails все не так уж плохо.
Я собираюсь создать простое приложение Rails и создать простую модель с некоторыми функциями. Затем я проведу вас через процесс написания теста для этой модели. Давайте начнем.
Структура и тесты Rails
Начнем с создания нового приложения Rails под названием alpaca_farmer.
rails new alpaca_farmer --database=postgresql
Если вы работаете с Rails, для вас не должно быть ничего нового в том, что при этом создается множество файлов и папок, но сегодня нас интересуют лишь некоторые из них:
./app/models
- это место, где будет жить наша модель, и где мы будем писать код, который хотим протестировать.
./test/models
здесь мы будем писать тесты.
И, наконец, ./tests/fixtures
- это то место, где мы создадим фальшивые данные для тестирования. Подробнее об этом позже.
Создадим нашу модель.
Автоматически созданные тестовые файлы
Rails поставляется с несколькими командами для автоматической генерации контента, и, возможно, наиболее полезной из них является generate model
, и это лучший способ сделать написание тестов для своей модели как можно проще.
Сначала мы запустим rails db:create
для создания базы данных, а затем воспользуемся generate model
для создания модели альпаки.
rails generate model Alpaca name sheared:boolean sweaters_made:integer # => Running via Spring preloader in process 46777 invoke active_record create db/migrate/20190221125632_create_alpacas.rb create app/models/alpaca.rb invoke test_unit create test/models/alpaca_test.rb create test/fixtures/alpacas.yml
Результат может показаться знакомым, потому что он создал для нас несколько файлов во всех папках, о которых я упоминал ранее. Он также создал для нас файл миграции, но я не буду вдаваться в подробности в этой статье. Все, что вам нужно знать об этом, это то, что теперь мы запустим rails db:migrate
, который будет использовать файл миграции для настройки нашей базы данных.
Напишем код
Теперь мы перейдем к автоматически сгенерированному .app/models/alpaca.rb
файлу, чтобы написать простой метод.
class Alpaca < ApplicationRecord def make_a_sweater if !self.sheared self.update(sheared: true, sweaters_made: self.sweaters_made += 1) else puts "This alpaca has no wool" end end end
Этот метод проверяет, острижена ли альпака. Если нет, он изменяет значение обрезки на истинное и добавляет единицу к количеству сделанных из него свитеров. Если он уже был стрижен, он просто выводит сообщение о том, что у альпаки нет шерсти.
Пришло время написать несколько тестов для этого метода. Это может занять некоторое время, так что обед из альпаки…
Хорошо, извиняюсь за отцовскую шутку, на самом деле это совсем не займет много времени. Как говорится в названии, Rails упрощает эту задачу.
Светильники и тестовая база данных
Ранее, когда мы запускали rails db:create
, он создал для нас две базы данных. Разработка и тестовая база данных. База данных для разработки - это та база данных, с которой вы можете поиграть, пока разрабатываете свое приложение, но нас интересует тестовая база данных.
В Rails многие из написанных нами методов предназначены для взаимодействия с базой данных, и для тестирования этих методов наши тесты взаимодействуют с тестовой базой данных. Однако, чтобы получить предсказуемые результаты наших тестов, база данных очищается в начале каждого запуска теста. Теперь вам может быть интересно, как можно проверить, нет ли данных. Вот тут-то и пригодятся светильники.
Давайте взглянем на наш автоматически созданный файл фикстуры ./test/fixtures/alpacas.yml
.
one: name: MyString sheared: false sweaters_made: 1 two: name: MyString sheared: false sweaters_made: 1
Это файл YAML, который, по сути, представляет собой просто удобочитаемый формат, используемый для хранения данных. В данном случае он используется для хранения наших фикстур, которые представляют собой просто объекты, которые помещаются в нашу базу данных после того, как она очищена для тестирования. Просто ради удовольствия, давайте напишем пару наших собственных приспособлений.
nata: name: Natalama sheared: false sweaters_made: 0 baldy: name: Baldy sheared: true sweaters_made: 3
Отлично, теперь у нас есть объект в тестовой базе данных для тестирования. Переходим к заключительной части: написание собственно теста.
Написание теста
Ясно, что Rails любит автоматически генерировать материалы для нас. У нас есть последний сгенерированный Rails файл, на который стоит взглянуть: ./test/models/alpaca_test.rb
.
require 'test_helper' class AlpacaTest < ActiveSupport::TestCase # test "the truth" do # assert true # end end
У нас есть require 'test_helper'
, который позволяет вам написать несколько вспомогательных методов в test_helper.rb
для использования в любом тесте. В этом примере мы этого делать не будем.
У нас также есть класс AlpacaTest
, который наследует свои функции от ActiveSupport::TestCase
.
Внутри этого класса, в настоящее время закомментированный, представляет собой полный, хотя и не очень полезный тест, но давайте раскомментируем его и рассмотрим его построчно.
test "the truth" do
Это настройка теста. Описательное название теста - «правда», и do
открывает блок.
assert true
Внутри блока есть утверждение. Это конкретное утверждение просто проверяет правдивость аргумента. Есть несколько утверждений, которые вы можете использовать, и вы можете включать столько утверждений, сколько вам нужно. Тест проходит, если все утверждения проходят. Вы можете перейти к документации Ruby для получения полного списка утверждений, которые вы можете использовать, но для этого теста мы будем использовать только assert иassert_equal(expected,actual)
, которые проверяют, ожидаемое == фактическое.
end
Тестовый блок закрыт.
Это был хороший пример того, как выглядит тест, но теперь давайте напишем его, чтобы протестировать созданный нами метод.
test "#make_a_sweater" do nata = Alpaca.find_by(name: "Natalama") baldy = Alpaca.find_by(name: "Baldy") nata_starting_sweaters = nata.sweaters_made baldy_starting_sweaters = baldy.sweaters_made nata.make_a_sweater baldy.make_a_sweater assert nata.sheared assert_equal nata_starting_sweaters + 1, nata.sweaters_made assert_equal baldy_starting_sweaters, baldy.sweaters_made end
Здесь мы устанавливаем переменные для наших альпак, Наталамы и Лысого из созданных нами приспособлений. Мы фиксируем их начальное количество свитеров, сделанных в переменной, и запускаем #make_a_sweater
для каждого из них. Затем напишем три утверждения.
assert nata.sheard
проверяет, соответствует ли значение Наталамы sheared
.
assert_equal nata_starting_sweaters + 1, nata.sweaters_made
гарантирует, что sweaters_made
Наталамы увеличится на единицу.
assert_equal baldy_starting_sweaters, baldy.sweaters_made
следит за тем, чтобы sweaters_made
Лысого оставался неизменным.
Теперь все, что нам нужно сделать, это запустить rails test
и посмотреть, как проходит тест!
Резюме
Были сделаны. Мы написали тест для нашего метода. Это было не так уж больно, правда? Вот что мы сделали для успешного тестирования нашего метода:
- Используется
rails generate
для создания пустых тестов и приспособлений вместе с моделью - Создал несколько настраиваемых приспособлений для запуска наших тестов.
- Написал тест, который запускал метод на наших фикстурах и использовал утверждения для проверки результатов метода.
Спасибо Rails за то, что сделали это легко, и спасибо, читатель, за чтение. Удачного кодирования и удачного тестирования!