问题
I'd like to override the get
and post
methods in RSpec.
I want to do this in order to deal with subdomains in my tests. As far as I can tell, the only way to deal with subdomains is to alter the @request
object before each call. I could do this before each and every test but that's going to lead to some really messy code.
In an effort to keep things DRY I've tried using a config.before(:each)
method in spec_helper.rb
however this doesn't seem to be run in the same scope as the test and doesn't have access to @request
.
My next bsest approach is therefore to overrride get
and post
which are in the correct scope.
def get *args
@request.host = @required_domain if @required_domain
super *args
end
I can include this code in the top of each spec file but I'd rather set it universally. If I set it in spec_helper.rb
though it does not get called.
Where can I set this to override the default get
method?
回答1:
however this doesn't seem to be run in the same scope as the test.
That's not quite right - it's run in the same scope, but before @request
is configured, so it has no effect.
Try this:
module RequestExtensions
def get(*)
@request.host = @required_domain if @required_domain
super
end
end
RSpec.configure do |c|
c.include RequestExtensions, :type => :controller
end
HTH, David
回答2:
I just ran into an issue which routed me to this question. The accepted solution guided me to the more effective implementation as of rack-test 0.6.3
.
I manually created ./spec/helpers/rspec_http_request_override_helper.rb
module RspecHttpRequestsOverrideHelper
def get(uri, params = {}, env = {}, &block)
super(uri, params, set_json_headers(env), &block)
end
def post(uri, params = {}, env = {}, &block)
super(uri, convert_to_json(params), set_json_headers(env), &block)
end
def put(uri, params = {}, env = {}, &block)
super(uri, convert_to_json(params), set_json_headers(env), &block)
end
def delete(uri, params = {}, env = {}, &block)
super(uri, convert_to_json(params), set_json_headers(env), &block)
end
# override other HTTP methods if necessary
private
def set_json_headers(env={})
env.merge({'ACCEPT' => "application/json", 'CONTENT_TYPE' => 'application/json'}) unless env.nil?
end
def convert_to_json(params={})
params.to_json unless params.nil?
end
end
Then I added the below to my spec_helper.rb
# require assuming project root is loaded into ruby's class paths
require './spec/helpers/rspec_http_request_override_helper'
RSpec.configure do |config|
config.include RspecHttpRequestsOverrideHelper
# Other settings
end
And that was it!
Note: The get
method above doesn't convert the params value to json intentionally. Param values are encoded into the query string and then sent. Not as part of the HTTP body in the request, even though the GET
http method supports sending a body; see here for more details.
My issue was that the rspec test helpers for an API I am building were converting boolean types to string types when sending the request to the API. Turns out when you don't specify a content-type header for json
the data is passed as multipart/form-data
or x-www-form-urlencoded
depending on the HTTP method; see here for more details. This was converting my special data types, which are valid in json like integers and booleans, into strings. And effectively needing me to convert them on the API's end. It wasn't until I added validation for the input into my API that this was exposed. Yay for validations and tests!
Now, I needed to effectively apply a content-type header to all my requests and convert the params to json when sending the requests; I was calling the http methods with the params value being a ruby hash. I have over 200 tests so going in an manually changing them all would not have been an optimal solution. So I implemented the below solution. Which works very well.
I decided to follow the same method definition as rack-test was and then I could effectively call super after editing the requests.
My failing tests now started passing and my previous tests where none the wiser.
Hopefully this helps others who run into a similar issue.
回答3:
The question betrays incorrect assumptions. You shouldn't be writing controller specs in the first place. This should all be done with Cucumber -- and in that case, you can just specify particular URLs, so the problem goes away.
来源:https://stackoverflow.com/questions/8447944/how-can-you-universally-override-the-get-and-post-methods-in-rspec