Testing Middleware with Rspec

11,364

You just need the world's simplest Rack app:

let(:app) { lambda {|env| [200, {'Content-Type' => 'text/plain'}, ['OK']]} }

Also, your middleware's constructor should receive an app as its first parameter not a hash so it should read:

subject { MyMiddleWare.new(app) }

In all likelihood, though, your test is going to need to determine what effect the middleware has had on the request. So you might write a slightly more sophisticated rack app to spy on your middleware.

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

and then you'll probably want to use Rack::MockRequest to actually send the request. Something like:

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
Share:
11,364

Related videos on Youtube

User314159
Author by

User314159

Oakland Native. Math guy turned computer programmer.

Updated on June 13, 2022

Comments

  • User314159
    User314159 almost 2 years

    I've written some Rack-Middleware and now I'm trying to test it with Rspec. But all Rack-Middleware is instantiated with an 'app' argument, that represents the Rails app itself. How do you guys mock this up in Rspec?

    For example,

     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
    
  • Calin
    Calin about 8 years
    There is no call to subject here, how does this actually work?
  • branch14
    branch14 about 8 years
    This is actually not a valid Rack app. The lambda would have to take an argument to be a valid Rack app.
  • Ritchie
    Ritchie about 8 years
    Fixed arity on simple code example - thanks @branch14.
  • SERGHII
    SERGHII over 2 years
    what is @request_headers for?