Четверг, 20 января 2022 23:27

RSpec. Тестируем форму отправки сообщений Rails

Оцените материал
(21 голосов)
RSpec. Тестируем форму отправки сообщений Rails
RSpec. Тестируем форму отправки сообщений Rails

 

Краткий этот док, как ясно уже из названия статьи, посвящен описанию процедуры тестирования формы отправки сообщений, опубликованной на одной из страничек вашего Ruby on Rails приложения; и предназначен как для новичков в деле программирования, так и для более зрелых их коллег, для которых навыки написания тестов не являются, назовем это так, сильной стороной (подобное случается, и нередко).

 

Вы в любой момент можете клонировать репозиторий CRUD-Blog и самостоятельно поэкспериментировать с кодом.

 

Процесс написания формы, которую мы с вами сегодня собрались тестировать, более-менее подробно описан в этих - тынц и тынц - материалах, с которых, возможно, и следует начать предлагаемый экскурс. Здесь же исходим из того, что формочка у вас уже имеет место быть и, идя наперекор канве TDD, необходимо написать тесты для нее (довольно распространенный, к слову сказать, в среде программистов подход).

 

Dev banner 1

 

Итак. Знакомство с RSpec - rspec-rails brings the RSpec testing framework to Ruby on Rails as a drop-in alternative to its default testing framework, Minitest - логично начать с инсталляции, добавив джем в :development и :test группы Gemfile:

 

# Gemfile
group :development, :test do
  gem 'rspec-rails', '~> 5.0.0'
end
# Download and install
$ bundle install
$ rails generate rspec:install

 

И далее, уже непосредственно для описываемых тестов, я запускаю еще две (эти модель и мэйлер, подчеркну, уже присутствуют в моем приложении) генерации:

 

$ rails g rspec:model contact
$ rails g rspec:mailer form

 

ОК. Файл модели Contact крайне несложен, содержит всего несколько валидаций формы:

 app/models/contact.rb

class Contact < ApplicationRecord
  validates :name, length: { minimum: 3 }
  validates :email, format: { with: /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i, on: :create }
  validates :subject, length: { minimum: 5 }
  validates :message, length: { minimum: 15 }
end

 

Соответственно, спек способен выглядеть (всегда возможны, разумеется, варианты) так:

spec/models/contact_spec.rb

require 'rails_helper'

RSpec.describe Contact, type: :model do
  subject(:contact) do
    Contact.new(
      name: 'test',
      email: Адрес электронной почты защищен от спам-ботов. Для просмотра адреса в браузере должен быть включен Javascript.',
      subject: 'something',
      message: 'Hi how are you doing?'
    )
  end
  before { contact.valid? }

  it 'requires an email' do
    expect(contact).to be_valid
    # other test on error message here perhaps?
  end

  it { is_expected.to validate_length_of(:name).is_at_least(3) }
  it { is_expected.to validate_length_of(:subject).is_at_least(5) }
  it { is_expected.to validate_length_of(:message).is_at_least(15) }
end

 

Запускаем тест, и он проходит:

 

bundle exec rspec spec/models/contact_spec.rb

....

Finished in 0.12443 seconds (files took 9.13 seconds to load)
4 examples, 0 failures

 

Контроллер contacts содержит, помимо прочего, следующий метод, передавая мэйлеру (либо не передавая) экземпляр класса Contact, т.е. параметры имя отправителя, его email, тему сообщения и, собственно, сам мессадж:

 

  def create
    @contact = Contact.new(contact_params)
    if verify_recaptcha
      respond_to do |format|
        if @contact.save
          FormMailer.new_form_email(@contact).deliver_now
          format.js   { flash.now[:success] = 'Thank you for your message.' }
        else
          format.js { flash.now[:error] = see_errors(@contact) }
        end
      end
    end
  end

app/mailers/form_mailer.rb

class FormMailer < ApplicationMailer
  def new_form_email(x)
    @form = x
    mail(to: ENV['SEND_EMAIL_TO'], subject: ENV['SUBJECT_EMAIL'])
  end
end

 

 Параметры отправки записаны в переменных окружения (environment variable); для этой цели я использую, в данном случае, gem 'figaro', хотя вы можете воспользоваться любым из доброго десятка иных способов сделать все то же самое:

config/application.yml

SEND_EMAIL_TO: Адрес электронной почты защищен от спам-ботов. Для просмотра адреса в браузере должен быть включен Javascript.'
SUBJECT_EMAIL: 'Hurray! You got a new form!'

 

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

spec/mailers/form_spec.rb

require 'rails_helper'

RSpec.describe FormMailer, type: :mailer do
  before(:each) do
    ActionMailer::Base.delivery_method = :test
    ActionMailer::Base.perform_deliveries = true
    ActionMailer::Base.deliveries = []
  end

  let(:form) do
    Contact.create!(
      name: 'test',
      email: Адрес электронной почты защищен от спам-ботов. Для просмотра адреса в браузере должен быть включен Javascript.',
      subject: 'subject',
      message: 'Bluh bluh bluh.'
    )
  end

  after(:each) do
    ActionMailer::Base.deliveries.clear
  end

  it 'should send an email' do
    FormMailer.new_form_email(form).deliver_now
    expect(ActionMailer::Base.deliveries.count).to eq(1)
  end

  it 'sends to the correct receiver' do
    FormMailer.new_form_email(form).deliver_now
    expect(ActionMailer::Base.deliveries.first.to.first).to eq(Адрес электронной почты защищен от спам-ботов. Для просмотра адреса в браузере должен быть включен Javascript.')
  end

  it 'should set the subject correctly' do
    FormMailer.new_form_email(form).deliver_now
    expect(ActionMailer::Base.deliveries.first.subject).to eq('Hurray! You got a new form!')
  end
end

 

Словом, три теста: для начала проверяем, собственно, сам процесс отправки, далее email администратора сайта и тему сообщения. Вкупе с описанными выше валидациями модели можем считать, что на данном этапе тесты вполне неплохо покрывают логику отправку сообщений с сайта... впрочем, сделаем для очистки совести еще и несложный тест контроллера, убедившись, что сервер успешно отдает страничку:

 

rails g rspec:controller contacts

spec/requests/contacts_spec.rb

require 'rails_helper'

RSpec.describe 'Contacts', type: :request do
  describe 'GET /contacts/index' do
    before do
      get '/contacts/index'
    end
    it 'returns http success' do
      expect(response).to have_http_status(:success)
    end
  end
end

 


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

Последнее изменениеЧетверг, 22 февраля 2024 15:55

Оставить комментарий

Добавьте ваш комментарий

Text To Speech

All sorts of things