Тестирование Middleware с Rspec
Я написал Rack-Middleware и сейчас пытаюсь протестировать его с помощью Rspec. Но все Rack-Middleware создается с помощью аргумента 'app', который представляет само приложение Rails. Как вы, ребята, издеваетесь над этим в Rspec?
Например,
describe MyMiddleWare do
let(:app) { # How do I mock a Rails app object here? }
subject { MyMiddleWare.new(app: app) }
it 'should blah blah blah' do
# a bunch of tests go here
end
end
4 ответа
Вам просто нужно самое простое в мире приложение Rack:
let(:app) { lambda {|env| [200, {'Content-Type' => 'text/plain'}, ['OK']]} }
Кроме того, конструктор промежуточного программного обеспечения должен получить приложение в качестве первого параметра, а не хеш, поэтому он должен читать:
subject { MyMiddleWare.new(app) }
Однако, по всей вероятности, вашему тесту потребуется определить, какое влияние промежуточное программное обеспечение оказало на запрос. Таким образом, вы могли бы написать немного более сложное стоечное приложение, чтобы шпионить за вашим промежуточным ПО.
class MockRackApp
attr_reader :request_body
def initialize
@request_headers = {}
end
def call(env)
@env = env
@request_body = env['rack.input'].read
[200, {'Content-Type' => 'text/plain'}, ['OK']]
end
def [](key)
@env[key]
end
end
и тогда вы, вероятно, захотите использовать Rack::MockRequest для фактической отправки запроса. Что-то вроде:
describe MyMiddleWare do
let(:app) { MockRackApp.new }
subject { described_class.new(app) }
context "when called with a POST request" do
let(:request) { Rack::MockRequest.new(subject) }
before(:each) do
request.post("/some/path", input: post_data, 'CONTENT_TYPE' => 'text/plain')
end
context "with some particular data" do
let(:post_data) { "String or IO post data" }
it "passes the request through unchanged" do
expect(app['CONTENT_TYPE']).to eq('text/plain')
expect(app['CONTENT_LENGTH'].to_i).to eq(post_data.length)
expect(app.request_body).to eq(post_data)
end
end
end
end
Я считаю, что вы должны использовать спецификации запросов, имитирующие HTTP-запросы (ваше промежуточное ПО должно быть включено в стек промежуточного ПО rails). Более подробную информацию о спецификациях запроса rspec смотрите здесь.
UPD Думаю, я нашел именно то, что вам нужно, с Test::Unit, но для RSpec легко переписать: rack-ssl -forcer
Я проверил мой так
describe Support::CharConverter do
let(:env_hash) do
{
"HTTP_REFERER" => "",
"PATH_INFO" => "foo",
"QUERY_STRING" => "bar",
"REQUEST_PATH" => "is",
"REQUEST_URI" => "here",
}
end
subject do
Support::CharConverter.new(env_hash)
end
context 'sanitize_env' do
it 'should keep key values the same if nothing to sanitize' do
sanitized_hash = subject.sanitize_env(env_hash)
# k = env_hash.keys[5]
# v = env_hash.values[5]
env_hash.each do |k, v|
sanitized_hash[k].encoding.name.should eq("US-ASCII")
sanitized_hash[k].should eq(v)
sanitized_hash[k].valid_encoding?.should eq(true)
end
end
end
end
Я пишу приложение Sinatra с промежуточным программным обеспечением, я пошел по пути @ritchie и в итоге создал приложение, которое выглядит так:
# Return the params in the response body as JSON
class ParamsInResponseApp < Sinatra::Base
def call(env)
super
rack_params = env["rack.request.query_hash"]
[200, {"Content-Type" => "application/json"}, [{"app" => rack_params}.to_json]]
end
end
Наследование от
Sinatra::Base
и звоню
super
позволил мне получить параметры из
env["rack.request.query_hash"]
, что было иначе
nil
.
Обратите внимание, что это приложение помещает параметры в ответ, поэтому я могу проверить их, не заглушая ничего.