Here is my rack application:
class MainAppLogic
def initialize
Rack::Server.start(:app =>Server, :server => "WEBrick", :Port => "8080")
end
end
class Server
def self.call(env)
return [200, {},["Hello, World"]]
end
end
When actually run, it behaves as it should and returns "Hello World" to all requests. I'm having trouble convincing rack-test to work with it. Here are my tests:
require "rspec"
require "rack/test"
require "app"
# Rspec config source: https://github.com/shiroyasha/sinatra_rspec
RSpec.configure do |config|
config.include Rack::Test::Methods
end
describe MainAppLogic do
# App method source: https://github.com/shiroyasha/sinatra_rspec
def app
MainAppLogic.new
end
it "starts a server when initialized" do
get "/", {}, "SERVER_PORT" => "8080"
last_response.body.should be != nil
end
end
When I test this, it fails complaining that MainAppLogic
is not a rack server, specifically, that it doesn't respond to MainAppLogic.call
. How can I let it know to ignore that MainAppLogic
isn't a rack server and just place a request to localhost:8080
, because there server has started?
First thing: why the custom class to run the app? You can use the rackup
tool, which is the de-facto standard for running Rack apps. Some more details on it here.
Your app code then becomes:
class App
def call(env)
return [200, {}, ['Hello, World!']]
end
end
and with the config.ru
require_relative 'app'
run App.new
you can start the app by running rackup
in your project's directory.
As for the error, the message is pretty clear. rack-test
expects, that the return value of app
method would be an instance of a rack app (an object that responds to call
method). Take a look what happens in rack-test
internals (it's pretty easy to follow, as a tip—focus on these in given order: lib/rack/test/methods.rb#L30
lib/rack/mock_session.rb#L7
lib/rack/test.rb#L244
lib/rack/mock_session.rb#L30
. Notice how the Rack::MockSession
is instantiated, how it is used when processing requests (e.g. when you call get
method in your tests) and finally how the call
method on your app is executed.
I hope that now it's clear why the test should look more like this (yes, you don't need to have a server running when executing your tests):
describe App do
def app
App.new
end
it "does a triple backflip" do
get "/"
expect(last_response.body).to eq("Hello, World")
end
end
P.S.
Sorry for the form of links to rack-test
, can't add more than 2 with my current points :P