2012-09-07 59 views
11

我正在編寫一個調用某些外部服務的Sinatra應用程序。我想很明顯我的測試,以避免調用真正的服務,讓此刻想我有這個在Sinatra應用程序中注入依賴關係

class MyApp < Sinatra::Base 
    get '/my_method' do 
    @result = ExternalServiceHandler.new.do_request 
    haml :my_view 
    end 
end 

而且在我的測試

describe "my app" do 
    include Rack::Test::Methods 
    def app() MyApp end 

    it "should show OK if call to external service returned OK" do 
    @external_service_handler = MiniTest::Mock.new 
    @external_service_handler.expect :do_request, "OK" 

    #Do the injection 

    get '/my_method' 
    response.html.must_include "OK" 
    end 

    it "should show KO if call to external service returned KO" do 
    @external_service_handler = MiniTest::Mock.new 
    @external_service_handler.expect :do_request, "KO" 

    #Do the injection 

    get '/my_method' 
    response.html.must_include "KO" 
    end 

end 

我能想到的兩種方式注入這一點。我可以調用實例方法或通過構造函數傳遞依賴項。無論如何,因爲機架似乎沒有給我訪問當前的應用程序實例,我發現這是不可能的。

我可以爲此聲明一個類方法,但如果可能的話,我寧願使用實例。爲了保持每種情況下可能有不同的注入,並避免可能會損害其他測試的全局狀態,如果我忘記回滾狀態。

有什麼辦法可以做到這一點?

在此先感謝。

+1

我喜歡你的第一個想法(直接調用實例方法)並且有類似的問題。我嘗試在測試中以正常的意義初始化我的應用,例如'app = MyApp.new',但我無法在這個實例上調用實例方法。在Sinatra :: Base中有什麼可以阻止公共實例方法? 編輯 - 如果你喜歡這種方法,這個線程可能會幫助你: http://stackoverflow.com/questions/12072865/calling-a-sinatra-app-instance-method-from-testcase –

回答

1

我終於有做到這一點

describe "my app" do 

    def app 
    @INSTANCE 
    end 

    before do 
    @INSTANCE ||= MyApp.new! 
    end 

    #tests here 

end 

雖然我並不特別喜歡使用新的!它正在工作的時候超載。我可以使用將與每個測試一起使用的實例.whatever_method

9

看起來好像有幾個選項。您可以通過構造函數傳遞依賴關係,也可以使用設置。

構造函數參數數量

class MyApp < Sinatra::Base 
    def initialize(app = nil, service = ExternalServiceHandler.new) 
     super(app) 
     @service = service 
    end 

    get "/my_method" do 
     @result = @service.do_request 
     haml :my_view 
    end 
end 

而且在規格:

describe "my app" do 
    include Rack::Test::Methods 

    let(:app) { MyApp.new(service) } 
    let(:service) { double(ExternalServiceHandler) } 

    context "when the external service returns OK" do 
     it "shows OK" do 
      expect(service).to receive(:do_request).and_return("OK") 

      get '/my_method' 
      response.html.must_include "OK" 
     end 
    end 

    context "when the external service returns KO" do 
     it "shows KO" do 
      expect(service).to receive(:do_request).and_return("KO") 

      get '/my_method' 
      response.html.must_include "KO" 
     end 
    end 
end 

設置

class MyApp < Sinatra::Base 
    configure do 
     set :service, ::ExternalServiceHandler.new 
    end 

    get "/my_method" do 
     @result = settings.service.do_request 
     haml :my_view 
    end 
end 

而且在規格:

describe "my app" do 
    include Rack::Test::Methods 

    let(:app) { MyApp.new } 
    let(:service) { double(ExternalServiceHandler) } 
    before do 
     MyApp.set :service, service 
    end 

    context "when the external service returns OK" do 
     it "shows OK" do 
      expect(service).to receive(:do_request).and_return("OK") 

      get '/my_method' 
      response.html.must_include "OK" 
     end 
    end 

    context "when the external service returns KO" do 
     it "shows KO" do 
      expect(service).to receive(:do_request).and_return("KO") 

      get '/my_method' 
      response.html.must_include "KO" 
     end 
    end 
end