Как протестировать методы управления контроллером с помощью RSpec в приложении Rails 5 API - PullRequest
0 голосов
/ 27 февраля 2019

У меня есть следующий модуль управления контроллерами:

#controllers/concerns/response.rb

module Response
  extend ActiveSupport::Concern

  def json_response(object, status = :ok, opts = {})
    response = {json: object, status: status}.merge(opts)
    render response
  end
...
end

ApplicationController включает его следующим образом:

class ApplicationController < ActionController::API
  include Response
...
end

Как можно протестировать вышеупомянутые методы беспокойства?Какими должны быть тесты RSpec (контроллер, запрос)?

Я попытался определить shared_examples следующим образом:

#spec/shared/json_response.rb

require 'rails_helper'

RSpec.shared_examples 'JSON Responsive controller' do |controller_class|
  let(:controller_class) { controller_class }

  it 'render JSON response' do
    expect(controller_class).to respond_to(:json_response)
  end
end

и использовать его в спецификации контроллера:

#spec/controllers/concerns/fake_controller.rb

require 'rails_helper'

class FakeController < ApplicationController
end

RSpec.describe FakeController, type: :controller do
  it_behaves_like 'JSON Responsive controller', FakeController
end

но это не с:

Failures:

  1) FakeController behaves like JSON Responsive controller render JSON response
     Failure/Error: expect(controller_class).to respond_to(:json_response)
       expected FakeController to respond to :json_response
     Shared Example Group: "JSON Responsive controller" called from ./spec/controllers/concerns/fake_controller_spec.rb:7
     # ./spec/shared/json_response.rb:7:in `block (2 levels) in <main>'

Finished in 0.23535 seconds (files took 1.11 seconds to load)
1 example, 1 failure

Чего мне не хватает?

1 Ответ

0 голосов
/ 27 февраля 2019

Вот решение, к которому я пришел, чтобы оно заработало.

  1. Создайте спецификацию контроллера в spec/controller/fake_controller_spec.rb следующим образом:
require 'rails_helper'

class FakeController < ApplicationController

  def render(*args)
    args.first
  end
end

RSpec.describe FakeController, type: :controller do
  it_should_behave_like "JSON Responsive controller", FakeController
end

Мне пришлосьпереопределить render(*args) метод для возможности вызова render изнутри Response модуля озабоченности.

Создайте спецификацию shared_examples в spec/shared/json_response.rb:
require 'rails_helper'

RSpec.shared_examples 'JSON Responsive controller' do |including_controller|
  let(:instance) { including_controller.new }

  it 'should respond to #json_response' do
    expect(instance).to respond_to(:json_response)
  end

  it 'should respond #respond_with_errors' do
    expect(instance).to respond_to(:respond_with_errors)
  end

  it 'should respond to #paginated_response_status' do
    expect(instance).to respond_to(:paginated_response_status)
  end

  context '#paginated_response_status' do
    it 'returns 200 if collection is not paginated' do
      expect(instance.paginated_response_status([1])).to eq :ok
    end

    it 'returns 206 if collection is paginated' do
      collection = (1..35).to_a
      expect(instance.paginated_response_status(collection)).to eq :partial_content
    end
  end

  context '#respond_with_errors' do
    it 'returns :unprocessable_entity status' do
      model = double(:model)
      errors = double(:errors, messages: {})
      allow(model).to receive(:errors).and_return(errors)
      response = instance.respond_with_errors(model)
      expect(response[:status]).to eq :unprocessable_entity
    end
  end

  context '#json_response' do
    it 'returns JSON with default :ok status' do
      model = double(:model)
      response = instance.json_response(model)
      expect(response[:status]).to eq :ok
    end

    it 'returns JSON with the specified status' do
      model = double(:model)
      response = instance.json_response(model, :partial_content)
      expect(response[:status]).to eq :partial_content
    end
  end
end

Обратите внимание: чтобы иметь возможность использовать общий пример, определенный в папке shared, необходимо добавить следующее к rails_helper.rbфайл:

Dir[Rails.root.join('spec/shared/**/*.rb')].each  { |f| require f }
...
RSpec.configure do |config|
..
end
Наконец, вот код для проверки, определенный в controllers/concerns/response.rb:
module Response
  extend ActiveSupport::Concern

  def json_response(object, status = :ok, opts = {})
    response = {json: object, status: status}.merge(opts)
    render response
  end

  def respond_with_errors(object)
    render json: { errors: ErrorSerializer.serialize(object) }, status: :unprocessable_entity
  end

  def paginated_response_status(collection)
    collection.size > WillPaginate.per_page ? :partial_content : :ok
  end
end

ErrorSerializer - это просто еще один модуль, который создает JSON для возврата в случае ошибок:

#controllers/concerns/error_serializer.rb

module ErrorSerializer
  extend ActiveSupport::Concern

  def self.serialize(object)
    object.errors.messages.map do |field, errors|
      errors.map do |error_message|
        {
          status: 422,
          title: 'Invalid attribute',
          source: { pointer: "/data/attributes/#{field}" },
          detail: error_message
        }
      end
    end.flatten
  end
end

Надеюсь, это поможет.

...