2012-07-11 97 views
9

我正在研究一个Rails应用,它具有JSON格式的REST API和版本(根据这个优秀的Ryan的演员:http://railscasts.com/episodes/350-rest-api-versioning)。Rspec:在路由规范中添加一些头部请求

例如,有一个规范/请求规格:

require 'spec_helper' 

describe "My Friends" do 
    describe "GET /my/friends.json" do 
    it "should get my_friends_path" do 
     get v1_my_friends_path, {}, {'HTTP_ACCEPT' => 'application/vnd.myapp+json; level=1'} 
     response.status.should be(401) 
    end 
    end 
end 

而且效果很好。但是(保持这个例子)我们如何编写路由规范?例如该规范是不正确的:

require 'spec_helper' 

describe "friends routing" do 
    it "routes to #index" do 
    get("/my/friends.json", nil, {'HTTP_ACCEPT' => 'application/vnd.myapp+json; level=1'}). 
     should route_to({ action: "index", 
        controller: "api/v1/private/my/friends", 
         format: "json" }) 
    end 
end 

我尝试不同的方法(如request.headers['Accept']@request.headers['Accept'],其中request是不确定的,@request为零);我真的不知道该怎么做。

我在Ruby 1.9.3,Rails 3.2.6和rspec-rails 2.11.0。谢谢。

回答

5

目前无法发送路由规格addititional头,它说,这是由于在actionpack-3.2.5/lib/action_dispatch/routing/route_set.rbline 608

env = Rack::MockRequest.env_for(path, {:method => method}) 

path是您请求的路径"/my/friends.json"和方法:get 产生的env包含的东西如下所示:

{ 
"rack.version"=>[1, 1], 
"rack.input"=>#<StringIO:0xb908f5c>, 
"rack.errors"=>#<StringIO:0xb908fac>, 
"rack.multithread"=>true, 
"rack.multiprocess"=>true, 
"rack.run_once"=>false, 
"REQUEST_METHOD"=>"GET", 
"SERVER_NAME"=>"your-url.com", # if path was http://your-url.com/ 
"SERVER_PORT"=>"80", 
"QUERY_STRING"=>"", 
"PATH_INFO"=>"/", 
"rack.url_scheme"=>"http", 
"HTTPS"=>"off", 
"SCRIPT_NAME"=>"", 
"CONTENT_LENGTH"=>"0" 
} 

如果你能模拟Rack::MockRequest::env_for应该可以注入除env_for生成的头之外的其他头(参见上面的哈希)。

除了目前正在使用的route_to匹配错了,你应该把它在一个Hash,你指定的方法和这样的路径:

{ get: '/' }.should route_to(controller: 'main', action: 'index') 

让我们知道,如果你能嘲笑出env_for并让它返回您的标题,将很高兴知道。

问候 克里斯托夫

+0

你是如何获得“无法修改冻结散列”错误的? – 2017-07-11 09:12:47

+0

我可能正在使用旧版本的rspec或ruby,其中哈希没有被冻结。 – 2017-07-14 12:06:43

5
before do 
    ActionDispatch::TestRequest::DEFAULT_ENV["action_dispatch.request.accepts"] = "application/vnd.application-v1+json" 
end 

after do 
    ActionDispatch::TestRequest::DEFAULT_ENV.delete("action_dispatch.request.accepts") 
end 
+0

你是如何获得“无法修改冻结哈希”错误的? – 2017-07-11 09:12:34

13

通过结合从克里斯托的和彼得的回答想法,我想出了为我工作的解决方案。我正在使用rspec和rails 3.0。

it 'should route like i want it to' do 
    Rack::MockRequest::DEFAULT_ENV["HTTP_ACCEPT"] = "*/*" 
    {get: "/foo/bar"}. 
    should route_to(
    controller: 'foo', 
    action: 'bar', 
) 
    Rack::MockRequest::DEFAULT_ENV.delete "HTTP_ACCEPT" 
end 
+0

你是如何获得“无法修改冻结哈希”错误的? – 2017-07-11 09:03:34

+0

@ChrisHough嗯,我不记得有这个错误。但请注意,这个解决方案是用于rails 3.你可能在4.x上,他们可能已经开始冻结那个DEFAULT_ENV hash ... – 2017-07-13 03:24:55

+0

是的,我不得不抛弃我的路由规范以获取请求规格。我完全没问题。 – 2017-07-13 15:41:26

2

可以使用的RSpec的and_wrap_original嘲笑Rack::MockRequest.env_for方法:

expect(Rack::MockRequest).to receive(:env_for).and_wrap_original do |original_method, *args, &block| 
    original_method.call(*args, &block).tap { |hash| hash['HTTP_ACCEPT'] = 'application/vnd.myapp+json; level=1' } 
end 
+1

这个解决方案为我工作在Rails 5 – justNeph 2016-10-19 15:14:34

+1

@justNeph你可以扩展你如何实现这个或你的spec是什么样子? – 2016-10-19 18:05:05

+0

您是如何获得“无法修改冻结哈希”错误的? – 2017-07-11 09:13:01

0

对于Rails的3和4我曾做过一个RSpec around hook如下:

around do |example| 
    Rack::MockRequest::DEFAULT_ENV['HTTP_ACCEPT'] = 'application/vnd.vendor+json; version=1' 

    example.run 

    Rack::MockRequest::DEFAULT_ENV.delete 'HTTP_ACCEPT' 
end 

由于Rack >= 2.0.3used by Rails 5Rack::MockRequest::DEFAULT_ENVhash is frozen

您可以重新定义常量和使用Kernel.silence_warnings沉默红宝石警告:

around do |example| 
    silence_warnings do 
    Rack::MockRequest::DEFAULT_ENV = Rack::MockRequest::DEFAULT_ENV.dup 
    end 

    Rack::MockRequest::DEFAULT_ENV['HTTP_ACCEPT'] = 'application/vnd.vendor+json; version=1' 

    example.run 

    Rack::MockRequest::DEFAULT_ENV.delete 'HTTP_ACCEPT' 
end 

这是一个有点劈,但它就像一个魅力。