Если вы похожи на меня, вы любите писать код. Вы могли бы делать это часами в день каждый день и чувствовать, что живете своей лучшей жизнью, но как насчет написания тестов для вашего кода? Вы просто съежились от одного упоминания об этом? Ничего страшного, если да. Я тоже несколько раз. Мы знаем, что тесты могут сэкономить нам много времени, когда мы вернемся к рефакторингу или добавлению функций, но иногда процесс их написания может показаться очень утомительным. Я здесь, чтобы показать вам, что, по крайней мере, с 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 за то, что сделали это легко, и спасибо, читатель, за чтение. Удачного кодирования и удачного тестирования!