2013-10-15 40 views
0

VCR Cucumber文檔顯示了很多使用小型Sinatra應用程序模擬遠程服務器的示例,使用從vcr_cucumber_helpers.rb加載的名爲start_sinatra_app的函數。我想在我的Rails/RSpec/VCR測試中使用類似的東西,但還沒有想出如何將start_sinatra_app(或等價物)放到我的測試框架中。我的幼稚方法不起作用,因爲 - 不出所料 - 它找不到vcr_cucumber_helpers.rb如何使用Sinatra模擬RSpec/VCR中的遠程服務器?

我需要添加什麼以使其在RSpec下工作?或者我是否在雜草中,這樣做是錯誤的?

# file: spec/app/models/sinatra_test_spec.rb 
require 'spec_helper' 

start_sinatra_app(:port => 7777) do 
    get("/") { "Hello" } 
end 

describe "sinatra rspec test" do 
    it 'calls the sinatra app' do 
    VCR.use_cassette("sinatra_rspec_test") do 
     res = Net::HTTP.get_response('localhost', "/", 7777) 
     res.body.should == 'Hello' 
    end 
    end 
end 

回答

1

Here's the code你正在尋找:

def start_sinatra_app(options, &block) 
    raise ArgumentError.new("You must pass a port") unless options[:port] 

    require 'sinatra' 
    require 'support/vcr_localhost_server' 
    klass = Class.new(Sinatra::Base) 
    klass.disable :protection 
    klass.class_eval(&block) 

    VCR::LocalhostServer.new(klass.new, options[:port]) 
end 

這反過來使用VCR::LocalhostServer

require 'rack' 
require 'rack/handler/webrick' 
require 'net/http' 

# The code for this is inspired by Capybara's server: 
# http://github.com/jnicklas/capybara/blob/0.3.9/lib/capybara/server.rb 
module VCR 
    class LocalhostServer 
    READY_MESSAGE = "VCR server ready" 

    class Identify 
     def initialize(app) 
     @app = app 
     end 

     def call(env) 
     if env["PATH_INFO"] == "/__identify__" 
      [200, {}, [VCR::LocalhostServer::READY_MESSAGE]] 
     else 
      @app.call(env) 
     end 
     end 
    end 

    attr_reader :port 

    def initialize(rack_app, port = nil) 
     @port = port || find_available_port 
     @rack_app = rack_app 
     concurrently { boot } 
     wait_until(10, "Boot failed.") { booted? } 
    end 

    private 

    def find_available_port 
     server = TCPServer.new('127.0.0.1', 0) 
     server.addr[1] 
    ensure 
     server.close if server 
    end 

    def boot 
     # Use WEBrick since it's part of the ruby standard library and is available on all ruby interpreters. 
     options = { :Port => port } 
     options.merge!(:AccessLog => [], :Logger => WEBrick::BasicLog.new(StringIO.new)) unless ENV['VERBOSE_SERVER'] 
     Rack::Handler::WEBrick.run(Identify.new(@rack_app), options) 
    end 

    def booted? 
     res = ::Net::HTTP.get_response("localhost", '/__identify__', port) 
     if res.is_a?(::Net::HTTPSuccess) or res.is_a?(::Net::HTTPRedirection) 
     return res.body == READY_MESSAGE 
     end 
    rescue Errno::ECONNREFUSED, Errno::EBADF 
     return false 
    end 

    def concurrently 
     # JRuby doesn't support forking. 
     # Rubinius does, but there's a weird issue with the booted? check not working, 
     # so we're just using a thread for now. 
     Thread.new { yield } 
    end 

    def wait_until(timeout, error_message, &block) 
     start_time = Time.now 

     while true 
     return if yield 
     raise TimeoutError.new(error_message) if (Time.now - start_time) > timeout 
     sleep(0.05) 
     end 
    end 
    end 
end 
+0

謝謝! - 對不起,我沒有及時注意到你的答案! –

0

Webmock做到這一點相當不錯。

允許連接到本地主機:

# spec/spec_helper.rb  
require 'webmock/rspec' 
WebMock.disable_net_connect!(allow_localhost: true) 

然後點你的URL到應用程序:

# spec/spec_helper.rb 
RSpec.configure do |config| 
    config.before(:each) do 
    stub_request(:any, /api.github.com/).to_rack(SinatraApp) 
    end 
end 

更清晰的示例,請參見:
http://robots.thoughtbot.com/how-to-stub-external-services-in-tests