Тестирование 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.

Обратите внимание, что это приложение помещает параметры в ответ, поэтому я могу проверить их, не заглушая ничего.

Другие вопросы по тегам