В приложении Rails 4.2.0, протестированном с rspec-rails
, я предоставляю веб-API JSON с REST-подобным ресурсом с обязательным атрибутом mand_attr
.
Я хотел бы проверить, что этот API отвечает кодом HTTP 400 (BAD REQUEST
), когда этот атрибут отсутствует в запросе POST. (См. второй пример удара.) Мой контроллер пытается вызвать этот код HTTP с помощью бросая ActionController::ParameterMissing
, как показано в первом примере RSpec ниже.
В других примерах RSpec я хочу, чтобы возникшие исключения были спасены примерами (если они ожидаются) или попали в средство выполнения тестов, чтобы они отображались разработчику (если ошибка неожиданная. ), поэтому я не хочу удалять
# Raise exceptions instead of rendering exception templates.
config.action_dispatch.show_exceptions = false
с config/environments/test.rb
.
Мой план состоял в том, чтобы иметь что-то вроде следующего в спецификации запроса:
describe 'POST' do
let(:perform_request) { post '/my/api/my_ressource', request_body, request_header }
let(:request_header) { { 'CONTENT_TYPE' => 'application/json' } }
context 'without mandatory attribute' do
let(:request_body) do
{}.to_json
end
it 'raises a ParameterMissing error' do
expect { perform_request }.to raise_error ActionController::ParameterMissing,
'param is missing or the value is empty: mand_attr'
end
context 'in production' do
###############################################################
# How do I make this work without breaking the example above? #
###############################################################
it 'reports BAD REQUEST (HTTP status 400)' do
perform_request
expect(response).to be_a_bad_request
# Above matcher provided by api-matchers. Expectation equivalent to
# expect(response.status).to eq 400
end
end
end
# Below are the examples for the happy path.
# They're not relevant to this question, but I thought
# I'd let you see them for context and illustration.
context 'with mandatory attribute' do
let(:request_body) do
{ mand_attr: 'something' }.to_json
end
it 'creates a ressource entry' do
expect { perform_request }.to change(MyRessource, :count).by 1
end
it 'reports that a ressource entry was created (HTTP status 201)' do
perform_request
expect(response).to create_resource
# Above matcher provided by api-matchers. Expectation equivalent to
# expect(response.status).to eq 201
end
end
end
Я нашел два рабочих и одно частично работающее решения, которые я отправлю в качестве ответов. Но я не особо доволен ни одним из них, поэтому, если вы можете придумать что-то получше (или просто другое), я хотел бы увидеть ваш подход! Кроме того, если спецификация запроса неправильный тип спецификации, чтобы проверить это, я бы хотел знать об этом.
Предвижу вопрос
Почему вы тестируете фреймворк Rails, а не только свое приложение Rails? У фреймворка Rails есть собственные тесты!
поэтому позвольте мне ответить на этот вопрос заранее: я чувствую, что я тестирую здесь не сам фреймворк, а то, правильно ли я использую фреймворк. Мой контроллер наследуется не от ActionController::Base
, а от ActionController::API
, и я не знал, использует ли ActionController::API
ActionDispatch::ExceptionWrapper
по умолчанию или мне сначала пришлось бы каким-то образом сказать своему контроллеру, чтобы он сделал это.