Зарегистрируйтесь для доступа к 15+ бесплатным курсам по программированию с тренажером

Testing Ruby: Полный Rails

Программа урока

  • Webmock
  • Тестирование JSON
Rails.application.routes.draw do
  namespace :api do
    namespace :v1 do
      get 'names/fetch', to: 'names#fetch', as: :fetch_name
    end
  end
end

# Простейший способ тестирования API
class Api::V1::NamesControllerTest < ActionDispatch::IntegrationTest
  test '#fetch' do
    get api_v1_fetch_name_url
    assert_response :success
  end
end

class Api::V1::NamesController < Web::ApplicationController
  def fetch
    render json: {
      country: '',
      possibility: 0.1
    }
  end
end

# Проверка содержимого ответа
class Api::V1::NamesControllerTest < ActionDispatch::IntegrationTest
  test '#fetch' do
    get api_v1_fetch_name_url
    json_response = JSON.parse(response.body)

    assert_response :success
    assert_equal 'RU', json_response['country']
    assert_equal 0.1, json_response['possibility']

    refute_nil json_response['country']
    refute_nil json_response['possibility']
  end
end

class Api::V1::NamesController < Web::ApplicationController
  def fetch
    result = FetchNameInformationService.new.(name: params[:name])
  end
end

# app/services/fetch_name_information_service.rb
# Сервис возвращает информацию об имени и верояность его использования в странах
# http://api.nationalize.io/?name=David

class FetchNameInformationService
  FETCH_NAME_BASE_URL = 'http://api.nationalize.io'
  def call(name:)
    uri = URI("#{FETCH_NAME_BASE_URL}?name=#{name}")
    response = Net::HTTP.get(uri)
    JSON.parse(response)
  rescue StandardError
    {
      country: nil,
      possibility: nil
    }
  end
end


# test/services/fetch_name_information_service_test.rb
require 'test_helper'
require_relative 'app/services/fetch_name_information_service.rb'

# При каждом запуске тестов выполняется реальный запрос к API
class FetchNameInformationServiceTest < ActiveSupport::TestCase
  test '#call' do
    result = FetchNameInformationService.new.(name: params[:name])

    assert result['country'].is_a? Array
  end
end

Webmock

# ./Gemfile
group :test do
  # https://github.com/bblimke/webmock
  gem "webmock"
end

# ./test/test_helper.rb
require 'webmock/minitest'

# test/services/fetch_name_information_service_test.rb
require 'test_helper'
require_relative 'app/services/fetch_name_information_service.rb'


# app/services/fetch_name_information_service.rb
# Сервис возвращает информацию об имени и верояность его использования в странах
# http://api.nationalize.io/?name=David

class FetchNameInformationService
  FETCH_NAME_BASE_URL = 'http://api.nationalize.io'
  def call(name:)
    uri = URI("#{FETCH_NAME_BASE_URL}?name=#{name}")
    response = Net::HTTP.get(uri)

    {
      country: response['country'][0]['country_id'],
      possibility: response['country'][0]['probability']
    }
  rescue StandardError
    {
      country: '',
      possibility: ''
    }
  end
end

# При каждом запуске тестов выполняется реальный запрос к API
class FetchNameInformationServiceTest < ActiveSupport::TestCase
  test '#call' do
    name = 'John'
    stub_request(:get, "#{FetchNameInformationService::FETCH_NAME_BASE_URL}?name=#{name}")
    result = FetchNameInformationService.new.(name: name)

    assert result[:country].is_a? String
    assert result[:possibility].is_a? String
  end
end

class Api::V1::NamesControllerTest < ActionDispatch::IntegrationTest
  test '#fetch' do
    name = 'David'
    stub_request(:get, "#{FetchNameInformationService::FETCH_NAME_BASE_URL}?name=#{name}")
    get api_v1_fetch_name_url(name: name)

    json_response = JSON.parse(response.body)

    assert_response :success
    assert json_response['country'].is_a?(String)
    assert json_response['possibility'].is_a?(String)
  end
end

# Webmock может подменять ответы от внешних сервисов.
stub_request(:get, "www.example.com").
  to_return({body: "abc"}, {body: "def"})
Net::HTTP.get('www.example.com', '/')    # ===> "abc\n"
Net::HTTP.get('www.example.com', '/')    # ===> "def\n"

Аватары экспертов Хекслета

Остались вопросы? Задайте их в разделе «Обсуждение»

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

Об обучении на Хекслете

Для полного доступа к курсу нужен базовый план

Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.

Получить доступ
1000
упражнений
2000+
часов теории
3200
тестов

Открыть доступ

Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно

  • 130 курсов, 2000+ часов теории
  • 1000 практических заданий в браузере
  • 360 000 студентов
Отправляя форму, вы принимаете «Соглашение об обработке персональных данных» и условия «Оферты», а также соглашаетесь с «Условиями использования»

Наши выпускники работают в компаниях:

Логотип компании Альфа Банк
Логотип компании Aviasales
Логотип компании Yandex
Логотип компании Tinkoff
Рекомендуемые программы
профессия
от 5 840 ₽ в месяц
Создание веб-приложений со скоростью света
5 месяцев
c опытом
Старт 4 апреля

Используйте Хекслет по-максимуму!

  • Задавайте вопросы по уроку
  • Проверяйте знания в квизах
  • Проходите практику прямо в браузере
  • Отслеживайте свой прогресс

Зарегистрируйтесь или войдите в свой аккаунт

Отправляя форму, вы принимаете «Соглашение об обработке персональных данных» и условия «Оферты», а также соглашаетесь с «Условиями использования»
Изображение Тото

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