Carles Jove Buxeda Carles Jove Buxeda - 4 months ago 12
Ruby Question

Set Up for RSpec in a Sinatra modular app

This is my first attempt with Sinatra. I built a simple classic app, set up RSpec for it, and got it working. Then, I tried to go modular, in a MVC fashion. Even though the app works in the browser, RSpec throws a

NoMethodError
. I've read Sinatra docs regarding RSpec, also searched a lot here in SO, but I can't find where the bug is. Any clue?

Thank you very much in advance.

Here are my relevant files:

config.ru

require 'sinatra/base'

Dir.glob('./{app/controllers}/*.rb') { |file| require file }

map('/') { run ApplicationController }


app.rb

require 'sinatra/base'

class ZerifApp < Sinatra::Base
# Only start the server if this file has been
# executed directly
run! if __FILE__ == $0
end


app/controllers/application_controller.rb

class ApplicationController < Sinatra::Base
set :views, File.expand_path('../../views', __FILE__)
set :public_dir, File.expand_path('../../../public', __FILE__)

get '/' do
erb :index
end
end


spec/spec_helper.rb

require 'rack/test'

# Also tried this
# Rack::Builder.parse_file(File.expand_path('../../config.ru', __FILE__))

require File.expand_path '../../app.rb', __FILE__

ENV['RACK_ENV'] = 'test'

module RSpecMixin
include Rack::Test::Methods
def app() described_class end
end

RSpec.configure { |c| c.include RSpecMixin }


spec/app_spec.rb

require File.expand_path '../spec_helper.rb', __FILE__

describe "My Sinatra Application" do
it "should allow accessing the home page" do
get '/'
expect(last_response).to be_ok
end
end


The error

My Sinatra Application should allow accessing the home page
Failure/Error: get '/'
NoMethodError:
undefined method `call' for nil:NilClass
# ./spec/app_spec.rb:5:in `block (2 levels) in <top (required)>'

Answer

I'm guessing you're following this recipe, correct?

The described_class in this line:

def app() described_class end

is meant to be the class under test, in this case ZerifApp. Try it like so:

def app() ZerifApp end

EDIT

It turns out the above answer is not correct about what described_class does. I assumed it was a placeholder -- actually it is an RSpec method that returns the class of the implicit subject, that is to say, the thing being tested.

The recipe at the link is misleading because of the way it recommends writing the describe block:

describe "My Sinatra Application" do

This is valid RSpec, but it does not define the subject class. Executing described_class in an example for this block will return nil. To make it work, replace the describe block:

describe ZerifApp do

Now described_class will return the expected value (ZerifApp)