Injecting dependencies in Sinatra app

I'm writing a Sinatra app that calls some external services. I want obviously my tests to avoid calling the real services so suppose at the moment I have this

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

And in my test

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

I can think of two ways to inject this. I can call an instance method or passing the dependency through constructor. Anyway since rack does not seem to give me access to current application instance I'm finding this impossible.

I can declare a class method for this but I'd prefer working with instances if possible. To keep potentially possible to have different injections in each case and avoiding global state that could harm other tests if I forget to rollback state.

Is there any way to accomplish this?

Thanks in advance.

Answers


It seems as though there are a couple of options. You can either pass the dependencies in through the constructor, or use settings.

Constructor Args

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

And in the spec:

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

Settings

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

And in the spec:

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

Need Your Help

Trying to fire a method in code behind on button click

c# asp.net

I am working on an ASP.NET project, I have a button that I want to fire a method in code behind to update database with updated client data when clicked.

Clang static analyzer gives warning over autoreleased

objective-c clang-static-analyzer

result = [result stringByReplacingOccurrencesOfString:@"ç" withString:@"c"];

About UNIX Resources Network

Original, collect and organize Developers related documents, information and materials, contains jQuery, Html, CSS, MySQL, .NET, ASP.NET, SQL, objective-c, iPhone, Ruby on Rails, C, SQL Server, Ruby, Arrays, Regex, ASP.NET MVC, WPF, XML, Ajax, DataBase, and so on.