Тестирование промежуточного ПО с Rspec - программирование
Подтвердить что ты не робот

Тестирование промежуточного ПО с 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
4b9b3361

Ответ 1

Вам просто нужно простое приложение для стойки в мире:

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

Ответ 2

Я считаю, что вам следует использовать спецификации запросов, имитирующие HTTP-запрос (ваше промежуточное ПО должно быть включено в стек промежуточного программного обеспечения rails). Подробнее о спецификациях запроса rspec здесь.

UPD Я думаю, что нашел именно то, что вам нужно, с Test:: Unit, но легко переписать для RSpec: rack-ssl-enforcer

Ответ 3

Я так протестировал мой

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