Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Testing on Rails with RSpec? #35

Closed
mockdeep opened this issue Dec 19, 2014 · 16 comments
Closed

Testing on Rails with RSpec? #35

mockdeep opened this issue Dec 19, 2014 · 16 comments
Labels

Comments

@mockdeep
Copy link

I'm having some trouble getting my controller tests passing, but RequestStore is not clearing out at the end of the request. I have the following code in my ApplicationController:

class ApplicationController < ActionController::Base
  before_action :store_event_context

private

  def store_event_context
    RequestStore[:event_context] = {
      ip_address: request.remote_ip,
      user_agent: request.user_agent,
      user: current_user,
    }
  end
end

And here are my specs:

describe ApplicationController, '#store_event_context' do

  controller do
    def index
      fail 'wut?' if params[:error]
      @event_context = RequestStore[:event_context]
      render nothing: true
    end
  end

  it 'stores event information for the request' do
    get(:index)
    expected_context = {
      ip_address: '1.2.3.4',
      user: nil,
      user_agent: 'Rails Testing',
    }
    expect(assigns(:event_context)).to eq(expected_context)
  end

  it 'clears out event information after the request' do
    get(:index)
    expect(RequestStore[:event_context]).to eq({})
  end

  it 'clears out event information if the request throws an error' do
    expect do
      get(:index, error: 'yep')
    end.to raise_error('wut?')
    expect(RequestStore[:event_context]).to eq({})
  end
end

The last two specs fail:

     Failure/Error: expect(RequestStore[:event_context]).to eq({})

       expected: {}
            got: {:ip_address=>"1.2.3.4", :user_agent=>"Rails Testing", :user=>nil}

I saw this bit in the readme about inserting it for Rack::Test and played around with that with no luck. Any idea how I can get this working?

@steveklabnik
Copy link
Owner

I don't really use RSpec, but I'll tweet about it to see if someone has an idea!

@mockdeep
Copy link
Author

Thanks!

@mockdeep
Copy link
Author

Hmm, may have found an unsatisfying answer to my own question: http://stackoverflow.com/questions/15026571/why-does-rspec-rails-skip-the-middleware

@stevenharman
Copy link

As the SO post says, controller tests skip the Rack stack and you'll need to use RSpec Request Specs if you need to fire the middleware stack.

@mockdeep
Copy link
Author

Hmm, yeah. I guess we can close this then.

@steveklabnik I don't know how much sense it makes, but any thought to moving this into the controller layer rather than having it be a middleware? By moving it to an around_action it makes it easier to test controllers in isolation without having to resort to weird hackery to get around it. I could see some subtle bugs popping up if a spec makes multiple requests, not to mention needing to have an after(:each) to clear out RequestStore.

@steveklabnik
Copy link
Owner

That would tie this to Rails as opposed to Rack.

@mockdeep
Copy link
Author

@steveklabnik Are Railties typically used outside of rails? I was thinking it would be possible to have the railtie set up an around_filter and leave the middleware untouched so it can still be used outside of rails. I updated it on my fork here: https://github.com/mockdeep/request_store/commit/fe5dadaf8c9d48cdd672949a4e7991aa633c33db

If it's something you think is appropriate to be part of this I can clean it up and pull request it.

@steveklabnik
Copy link
Owner

We only inject railties into Rails projects, so it'd have to be the same thing here.

I'm not sure I'm interested in making the code arguably worse (around filters are not the way this is supposed to be done) to satisfy an rspec edge case.

@stevenharman
Copy link

I'm not sure I'm interested in making the code arguably worse (around filters are not the way this is supposed to be done) to satisfy an rspec edge case.

Agreed. I wonder if an addition to the README on "testing in Rails" or something would suffice. Specifically it could address needing to use RSpec Request Specs, rather than controller specs, as this Gem needs the Rack middleware to work.

I assume something similar needs to be said about Rails + MiniTests controller vs. functional tests? (I've not used the standard test stack in Rails in a long time, so someone else should confirm/deny.)

@steveklabnik
Copy link
Owner

Yeah, I wouldn't mind a README note.

@mockdeep
Copy link
Author

@steveklabnik @stevenharman I'm not too familiar with middleware. Why is something like this not "supposed" to be solved with an around filter? I guess my rationale was that if the mess is being made in the application layer, it would be good to have it being cleaned up there, too. Though admittedly my motivation was testability.

@stevenharman
Copy link

RequestStore is intended to be a lower-level component of your application stack, operating at the Rack level makes it available to all portions of your stack which are built upon Rack. For example, mounted Sinatra apps, or other mounted Rails Engines.

On the other hand, Rails' controller around filters are only useful to the portion of your code which lives w/in controllers.

@mockdeep
Copy link
Author

So would you use it for passing data between your different services?

@steveklabnik
Copy link
Owner

It's more that if it's a middleware, your entire application can rely on this behavior. If it's in the controller, only your controller can.

@0xCCD
Copy link

0xCCD commented Feb 16, 2015

You can also clear it by your self

  before(:each) do
    RequestStore.clear!
  end

to your spec_helper.rb

RSpec.configure do |config|
  *
end

@mockdeep
Copy link
Author

Yeah, we have that in our spec helper. The issue is that we can't really test that it's working for us unless we find some way of doing it through an integration spec.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants