我有以下控制器关注模块:
#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
我想念什么?
答案 0 :(得分:0)
这是我要使其工作的解决方案。
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
。
spec/shared/json_response.rb
中创建一个shared_examples规范: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
希望这会有所帮助。