Как проверить ответ JSON с помощью RSpec?
В моем контроллере есть следующий код:
format.json { render :json => {
:flashcard => @flashcard,
:lesson => @lesson,
:success => true
}
В моем тесте контроллера RSpec я хочу проверить, что определенный сценарий действительно получил успешный ответ json, поэтому у меня была следующая строка:
controller.should_receive(:render).with(hash_including(:success => true))
Хотя при выполнении моих тестов я получаю следующую ошибку:
Failure/Error: controller.should_receive(:render).with(hash_including(:success => false))
(#<AnnoController:0x00000002de0560>).render(hash_including(:success=>false))
expected: 1 time
received: 0 times
Я проверяю ответ неправильно?
Ответы
Ответ 1
Вы можете проверить объект ответа и убедиться, что он содержит ожидаемое значение:
@expected = {
:flashcard => @flashcard,
:lesson => @lesson,
:success => true
}.to_json
get :action # replace with action name / params as necessary
response.body.should == @expected
ИЗМЕНИТЬ
Изменение этого параметра на post
делает его немного сложнее. Вот способ справиться с этим:
it "responds with JSON" do
my_model = stub_model(MyModel,:save=>true)
MyModel.stub(:new).with({'these' => 'params'}) { my_model }
post :create, :my_model => {'these' => 'params'}, :format => :json
response.body.should == my_model.to_json
end
Обратите внимание, что mock_model
не отвечает на to_json
, поэтому требуется либо stub_model
, либо экземпляр реальной модели.
Ответ 2
Вы можете проанализировать тело ответа следующим образом:
parsed_body = JSON.parse(response.body)
Затем вы можете сделать свои утверждения против этого проанализированного контента.
parsed_body["foo"].should == "bar"
Ответ 3
Создание ответа Кевина Троубриджа
response.header['Content-Type'].should include 'application/json'
Ответ 4
Также существует драгоценный камень json_spec, который стоит посмотреть
https://github.com/collectiveidea/json_spec
Ответ 5
Простой и простой способ сделать это.
# set some variable on success like :success => true in your controller
controller.rb
render :json => {:success => true, :data => data} # on success
spec_controller.rb
parse_json = JSON(response.body)
parse_json["success"].should == true
Ответ 6
Вы можете посмотреть в заголовок 'Content-Type'
, чтобы убедиться, что это правильно?
response.header['Content-Type'].should include 'text/javascript'
Ответ 7
Другой подход к тестированию только для ответа JSON (а не того, что содержание внутри содержит ожидаемое значение), заключается в анализе ответа с помощью ActiveSupport:
ActiveSupport::JSON.decode(response.body).should_not be_nil
Если ответ не обрабатывается JSON, будет выбрано исключение, и тест завершится с ошибкой.
Ответ 8
При использовании Rails 5 (в настоящее время все еще в бета-версии) есть новый метод parsed_body
в ответе на тест, который возвращает ответ, обработанный как то, что был закодирован последним запросом.
Передача на GitHub: https://github.com/rails/rails/commit/eee3534b
Ответ 9
Вы также можете определить вспомогательную функцию внутри spec/support/
module ApiHelpers
def json_body
JSON.parse(response.body)
end
end
RSpec.configure do |config|
config.include ApiHelpers, type: :request
end
и используйте json_body
, когда вам нужно получить доступ к ответу JSON.
Например, внутри вашей спецификации запроса вы можете использовать ее напрямую
context 'when the request contains an authentication header' do
it 'should return the user info' do
user = create(:user)
get URL, headers: authenticated_header(user)
expect(response).to have_http_status(:ok)
expect(response.content_type).to eq('application/vnd.api+json')
expect(json_body["data"]["attributes"]["email"]).to eq(user.email)
expect(json_body["data"]["attributes"]["name"]).to eq(user.name)
end
end
Ответ 10
Я нашел здесь клиентский помощник: https://raw.github.com/gist/917903/92d7101f643e07896659f84609c117c4c279dfad/have_content_type.rb
Поместите его в spec/support/matchers/have_content_type.rb и убедитесь, что загрузите материал из поддержки с чем-то вроде этого в spec/help.rb
Dir[Rails.root.join('spec/support/**/*.rb')].each {|f| require f}
Вот код сам, на всякий случай он исчез из данной ссылки.
RSpec::Matchers.define :have_content_type do |content_type|
CONTENT_HEADER_MATCHER = /^(.*?)(?:; charset=(.*))?$/
chain :with_charset do |charset|
@charset = charset
end
match do |response|
_, content, charset = *content_type_header.match(CONTENT_HEADER_MATCHER).to_a
if @charset
@charset == charset && content == content_type
else
content == content_type
end
end
failure_message_for_should do |response|
if @charset
"Content type #{content_type_header.inspect} should match #{content_type.inspect} with charset #{@charset}"
else
"Content type #{content_type_header.inspect} should match #{content_type.inspect}"
end
end
failure_message_for_should_not do |model|
if @charset
"Content type #{content_type_header.inspect} should not match #{content_type.inspect} with charset #{@charset}"
else
"Content type #{content_type_header.inspect} should not match #{content_type.inspect}"
end
end
def content_type_header
response.headers['Content-Type']
end
end