2012-07-11 28 views
9

Tôi đang làm việc trên ứng dụng Rails có API REST ở định dạng JSON và được phiên bản (theo diễn viên Ryan tuyệt vời này: http://railscasts.com/episodes/350-rest-api-versioning).Rspec: thêm một số yêu cầu tiêu đề bên trong thông số định tuyến

Ví dụ, có một spec/yêu cầu spec:

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 

Và nó hoạt động tốt. Nhưng (giữ ví dụ này) làm thế nào chúng ta có thể viết spec định tuyến? Ví dụ spec này là không đúng:

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 

tôi đã cố gắng nhiều cách khác nhau (chẳng hạn như request.headers['Accept']@request.headers['Accept'], nơi request là undefined và @request là con số không); Tôi thực sự không thấy làm thế nào để làm.

Tôi đang sử dụng Ruby 1.9.3, Rails 3.2.6 và rspec-rails 2.11.0. Cảm ơn.

Trả lời

5

Hiện nay bạn không thể gửi Headers addititional trong thông số kỹ thuật định tuyến, điều này là do line 608 trong actionpack-3.2.5/lib/action_dispatch/routing/route_set.rb nơi nó nói:

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

path là con đường yêu cầu của bạn "/my/friends.json" và phương pháp là :get Kết quả là env chứa một cái gì đó như sau:

{ 
"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" 
} 

Nếu bạn có thể thử Rack::MockRequest::env_for nên có thể tiêm các tiêu đề khác so với các tiêu đề được tạo bởi env_for (xem Hash ở trên).

Ngoài ra bạn hiện đang sử dụng khớp route_to sai, bạn nên gọi nó trên một Hash nơi bạn chỉ định các phương pháp và con đường như thế này:

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

Cho chúng tôi biết nếu bạn đã có thể Mock ra rằng env_for và để cho nó trở về tiêu đề của bạn, sẽ được tốt đẹp để biết.

Trân Christoph

+0

Làm thế nào bạn vượt qua được lỗi "không thể sửa đổi lỗi đóng băng"? –

+0

Tôi có thể đang sử dụng phiên bản cũ hơn của rspec hoặc ruby, nơi băm không bị đóng băng. –

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

Làm thế nào bạn vượt qua được lỗi "không thể sửa đổi lỗi đóng băng"? –

13

Bằng cách kết hợp các ý tưởng từ câu trả lời Piotr của của Cristophe và, tôi đã đưa ra một giải pháp mà làm việc cho tôi. Tôi đang sử dụng rspec và 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

Làm thế nào bạn vượt qua được lỗi "không thể sửa đổi lỗi đóng băng"? –

+0

@ChrisHough Hmm, tôi không nhớ có lỗi đó. Nhưng lưu ý rằng giải pháp này là cho đường ray 3. Bạn có khả năng trên 4.x và họ có thể đã bắt đầu đóng băng mà DEFAULT_ENV băm kể từ đó ... –

+0

Vâng, tôi đã phải bỏ thông số kỹ thuật định tuyến của tôi để yêu cầu thông số kỹ thuật. Đó là hoàn toàn tốt đẹp của tôi. –

2

Bạn có thể sử dụng rspec của and_wrap_original để chế nhạo các Rack::MockRequest.env_for phương pháp:

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

Giải pháp này làm việc cho tôi trong Rails 5 – justNeph

+1

@justNeph bạn có thể mở rộng về cách bạn triển khai thực hiện điều này hay thông số kỹ thuật của bạn trông như thế nào? –

+0

Làm thế nào bạn vượt qua được lỗi "không thể sửa đổi lỗi đóng băng"? –

0

Đối với Rails 3 và 4 Tôi đã làm như sau trong một 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 

Kể từ Rack >= 2.0.3 (used by Rails 5) Rack::MockRequest::DEFAULT_ENVhash is frozen.

Bạn có thể xác định lại liên tục và sử dụng Kernel.silence_warnings để bịt miệng những lời cảnh báo Ruby:

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 

Đó là một chút hack nhưng nó hoạt động như một nét duyên dáng.

Các vấn đề liên quan