Access Sinatra settings from Minitest test_helper - ruby

I am trying to access a variable defined in Sinatra settings from my test helper with no luck. This is my code:
Main app:
require 'sinatra'
set :foo, 'bar'
# use settings.foo in the routes
tests/test_helper.rb
ENV['RACK_ENV'] = 'test'
require 'minitest/autorun'
require 'rack/test'
module Minitest
class Spec
include Rack::Test::Methods
def app
Sinatra::Application
end
before do
# do something with settings.foo
end
end
end
I have tried Sinatra::Application.settings.foo and also app.settings.foo but none work.
I have also tried adding a helper method like the one below:
lib/helpers/settings_helper.rb
module SettingsHelper
def foo
settings.foo
end
end
helpers SettingsHelper
This works inside app, but again doesn't work inside test_helper. I tried requiring settings_helper.rb in test_helper. Also added an include. None of this worked.
Does anybody know what am I doing wrong?
Happy holidays

Not sure if this will work with a classic style app. But with a modular app you can do MyApp.set :foo, 'bar'. So you could try Sinatra::Application.set :foo, 'bar'
Hope this helps.

Related

Sinatra-Contrib: undefined method `namespace'

I'm new to TDD, and I'm trying to write methods to generate URLs on a per-class basis that inherit from a parent class using Sinatra and the Namespace library in Sinatra-Contrib. I'm not too far along, because I've gotten a failed RSpec test that has kept me from moving further: undefined method 'namespace'. Can anyone help?
Gemfile:
source 'https://rubygems.org'
ruby '1.9.3'
gem 'sinatra'
gem 'sinatra-contrib'
gem 'rack'
gem 'thin'
group :development, :test do
gem 'rspec'
gem 'rack-test'
gem 'ZenTest'
gem 'autotest-growl'
gem 'autotest-fsevent'
end
base_model.rb:
require 'sinatra'
require 'sinatra/namespace'
require 'rack'
def generate_routes_for_model(model_class, rootUrl)
namespace rootUrl do
get '/show' do
"I'm the model's show route"
end
end
end
base_model_spec.rb
require_relative '../base_model.rb'
require 'rack/test'
set :environment, :test
class Foo
end
def app
Sinatra::Application
end
include Rack::Test::Methods
describe 'Create Routes for test Class' do
it "should load foo.show" do
generate_routes_for_model(Foo, '/foo')
get '/foo/show'
last_response.should be_ok
end
end
Here's the result of the test:
Failures:
1) Create Routes for test Class should load foo.show
Failure/Error: generate_routes_for_model(Foo, '/foo')
NoMethodError:
undefined method `namespace' for #<RSpec::Core::ExampleGroup::Nested_2:0x007f8571102e00>
# ./base_model.rb:16:in `generate_routes_for_model'
# ./spec/base_model_spec.rb:24:in `block (2 levels) in <top (required)>'
It appears to be a scope problem, on first look. namespace is a class method of a Sinatra extension (which is why you call it within the class definition and not inside an instance method).
When you run RSpec, is namespace ever within a class that inherits from Sinatra::Base? I don't think so. You need to provide a Sinatra class that namespace can run within. e.g.
class Foo; end
app = Sinatra.new do
register Sinatra::Namespace
end
def generate_routes_for_model(app_class, model_class, rootUrl)
['show'].each do |route|
app_class.namespace rootUrl do
get route do
"I'm the model's show route"
end
end
end
end
generate_routes_for_model app, Foo, "/"
app.run!
Then going to http://localhost:4567/show will respond with "I'm the model's show route".
Or perhaps use class_eval to define the code, there's a few ways you could tackle this, main thing to keep in mind is make sure the scope is right or the app or RSpec etc won't be able to find the method.
Edit:
Also, I'd move the generation into a before block, as it's set up for an integration test (you're essentially saying "If the route exists then the generation worked, I don't need to test the method here", so it's a black box test of the public API - an integration test by any other name:) If you wanted to test the method itself that would be a unit test, and you'd need to look into the app to see the routes had been generated.
describe 'Create Routes for test Class' do
before do
generate_routes_for_model(Foo, '/foo')
get '/foo/show' # this, too, is not a test but a pre-requisite for the test
end
it "should load foo.show" do
last_response.should be_ok
end
end

simpler way to test my simple Rack app?

i have a Rack app like this:
app = Rack::Builder.new do
map '/' do
# ...
end
map '/edit' do
# ...
end
end.to_app
How would i test it without long-tail installation/setup/learn process.
RSpec and minitest are really great, but i do not really want to learn nor setup them.
Is there something i cat just plug in and write/run tests right away in plain Ruby?
I want to write tests as simple as i wrote the app above, without advanced techniques and gotchas.
In KISS I Trust!
you can try Specular + Sonar bundle.
Specular is for writing tests anywhere you need them.
Sonar is a mock "browser" that communicate to your app, just like rack-test does, but with some unique features and simpler workflow.
Using them is as simple as:
...
app.to_app
Spec.new do
include Sonar
app(app)
get
check(last_response.status) == 200
# etc...
end
puts Specular.run
so you put your specs right beside your app and write tests quickly in plain Ruby, without having to learn anything.
see the full example running at CIBox
(if it does not run automatically, click Run button)
PS: writing Rack apps this way is kinda a pain.
You can try a mapper, like Appetite one.
so your app may look like this:
class App < Appetite
map :/
def index
'index'
end
def edit
'edit'
end
end
see the same example but with app built by Appetite here
Simplest? Use Rack::Test with Test::Unit. gem install rack-test and run with ruby filename.rb
require "test/unit"
require "rack/test"
class AppTest < Test::Unit::TestCase
include Rack::Test::Methods
def app
Rack::Builder.new do
map '/' do
run Proc.new {|env| [200, {'Content-Type' => 'text/html'}, "foo"] }
end
map '/edit' do
# ...
end
end.to_app
end
def test_index
get "/"
assert last_response.ok?
end
end
Update: RSpec style requested - gem install rspec; run with rspec filename.rb
require 'rspec'
require 'rack/test'
describe 'the app' do
include Rack::Test::Methods
def app
Rack::Builder.new do
map '/' do
run Proc.new {|env| [200, {'Content-Type' => 'text/html'}, "foo"] }
end
map '/edit' do
# ...
end
end.to_app
end
it 'says foo' do
get '/'
last_response.should be_ok
last_response.body.should == 'foo'
end
end
You could use rack-test but that again entails using minitest/unit test but is the most common way testing Rack apps.

How to use RSpec to test a Sinatra application within a gem?

I am writing a gem which includes a Sinatra application that a developer can extend. For example:
# gem code:
require 'sinatra'
module Mygem
class Application < Sinatra::Base
get 'auth/login' {}
get 'auth/logout {}
end
end
# developer code:
require 'mygem'
class DeveloperApp < Mygem::Application
# ..
end
I am also getting started using RSpec. How should I configure RSpec for testing this functionality?
The references above are all informative and useful but mostly rails specific. I found it quite hard to find a simple recipe for a basic test of a modular Sinatra app, so I am hoping this will answer the question for others. Here is a completely bare-bones, small as possible test. This is probably not the only way to do it, but it works well for a modular app:
require 'sinatra'
class Foo < Sinatra::Base
get '/' do
"Hello"
end
end
require 'rack/test'
describe Foo do
include Rack::Test::Methods
def app
Foo.new
end
it "should be testable" do
get '/'
last_response.should be_ok
end
end
Note that there is no need to have the server running when you launch the test (some tutorials I saw implied that you do) - it's not an integration test.
It's actually pretty simple -- just add rspec to your gemfile (then bundle install), and make a directory in your gem called spec/. Once you've done that, add a file spec/spec_helper.rb that contains some configuration for rspec (mostly requiring various files from your library) as well as defining some helper methods for your specs. Then, for each model and controller, make a file called my_model_name_spec.rb or my_controller_name_spec.rb, and do the test there.
Here are some useful resources for getting started with rspec:
Railscasts:
http://railscasts.com/episodes/275-how-i-test
http://railscasts.com/episodes/71-testing-controllers-with-rspec
http://railscasts.com/episodes/157-rspec-matchers-macros/
And for some more advanced (but well-explained) stuff:
http://benscheirman.com/2011/05/dry-up-your-rspec-files-with-subject-let-blocks
Be sure to include the rack-test gem.
You spec helper should have:
require 'rack/test'
require 'foo' # or where ever your app is
# This can go in a helper somewhere
module AppHelper
def app
Foo.new
end
end
RSpec.configure do |config|
config.include Rack::Test::Methods
config.include AppHelper
end
Then, your spec can be as follows:
require 'spec_helper'
# Example app. Delete this example.
class Foo < Sinatra::Base
get '/' do
'Jesse Pinkman'
end
end
describe Foo do
it 'is testable' do
get '/' do
expect(last_response).to be_ok
end
end
end

The InstanceMethods module inside ActiveSupport::Concern.. Deprecation Warning

I have a portfolio website built in Sinatra. I haven't worked on it for a while, been doing some Rails. I updated my gem list yesterday by running 'gem update'. I don't know if this has anything to do with that, but I started working on the portfolio website again today and I've been getting some deprecation warnings.
DEPRECATION WARNING: The InstanceMethods module inside
ActiveSupport::Concern will be no longer included automatically.
Please define instance methods directly in Work instead. (called from
include at /Users/joris/Desktop/sinatra/portfolio/models/work.rb:2)
I'm not sure how to fix this and when I run the application it doesn't work anymore.. going to my routes just returns the Sinatra 404 page. (Also, isn't ActiveSupport part of Rails? Why is this coming up in my Sinatra app..)
The file it mentions in the error is work.rb:
class Work
include MongoMapper::Document
key :title, String
key :url, String
key :filename, String
key :file, String
key :description, String
timestamps!
end
This is my main file (portfolio.rb):
require "sinatra"
require 'twitter'
require 'RedCloth'
require 'html_truncator'
require 'digest/md5'
class Portfolio < Sinatra::Application
require_relative 'config/init'
require_relative 'helpers/init'
require_relative 'models/init'
require_relative 'routes/init'
The models init file (which calls the work.rb file) has these contents:
require 'mongo_mapper'
MongoMapper.connection = Mongo::Connection.new('lalaland.com', 10070)
MongoMapper.database = 'hello'
MongoMapper.database.authenticate('lalala', 'hello')
require_relative 'post'
require_relative 'work'
EDIT: Just saw I'm also getting it for models/post.rb
DEPRECATION WARNING: The InstanceMethods module inside
ActiveSupport::Concern will be no longer included automatically.
Please define instance methods directly in Post instead. (called from
include at /Users/joris/Desktop/sinatra/portfolio/models/post.rb:2)
Somewhere in your app (or its dependencies) you're doing
module Blah
extend ActiveSupport::Concern
module InstanceMethods
def foo
end
end
...
end
and Active Support is telling you to do
module Blah
extend ActiveSupport::Concern
def foo
end
end
You're right that Active Support is part of Rails, but like Active Record it can also be used without the rest of rails. Mongo mapper uses it for example, and at a cursory glance it uses the deprecated InstanceMethods idiom in a bunch of places
It looks like this was patched earlier this month in the mongo_mapper gem, so I would expect the fix to make it into the next release:
https://github.com/jnunemaker/mongomapper/commit/d2333d944ce6ae59ecab3c45e25bbed261f8180e

How do I configure RSpec with Sinatra to dynamically determine which Sinatra app is running before my test suite runs?

Ok so. I'm wanting to do request specs with RSpec for my Sinatra app.
I have a config.ru
# config.ru
require File.dirname(__FILE__) + '/config/boot.rb'
map 'this_route' do
run ThisApp
end
map 'that_route' do
run ThatApp
end
The boot.rb just uses Bundler and does additional requires for the rest of the app:
ThisApp looks like:
# lib/this_app.rb
class ThisApp < Sinatra::Base
get '/hello' do
'hello'
end
end
So I'm using RSpec and I want to write request specs like:
# spec/requests/this_spec.rb
require_relative '../spec_helper'
describe "This" do
describe "GET /this_route/hello" do
it "should reach a page" do
get "/hello"
last_response.status.should be(200)
end
end
it "should reach a page that says hello" do
get "/hello"
last_response.body.should have_content('hello')
end
end
end
end
This works fine because my spec_helper.rb is setup as follows:
# spec/spec_helper.rb
ENV['RACK_ENV'] = "test"
require File.expand_path(File.dirname(__FILE__) + "/../config/boot")
require 'capybara/rspec'
RSpec.configure do |config|
config.include Rack::Test::Methods
end
def app
ThisApp
end
But my problem is that I want to test "ThatApp" from my rackup file along with any amount more apps I might add later along with "ThisApp". For example if I had a second request spec file:
# spec/requests/that_spec.rb
require_relative '../spec_helper'
describe "That" do
describe "GET /that_route/hello" do
it "should reach a page" do
get "/hello"
last_response.status.should be(200)
end
end
it "should reach a page that says hello" do
get "/hello"
last_response.body.should have_content('hello')
end
end
end
end
RackTest requires the rack app I'm testing be defined in the spec_helper file with that 'app' method, and I think eventually I'm going to have to feed Capybara.app the same thing as well when doing further request specs with it.
I feel like I'm missing something and maybe there's an easy way to setup 'app' for RackTest and Capybara at runtime depending on what route and consequent rack app I'm testing in my request specs. Like a before filter in RSpec.configure maybe, but I can't think of or find how I'd access what rack app is currently loaded and try and set it there before the test suite runs.
Anyone get what I'm trying to do and can think of something? Thanks for any help.
Define a different helper module for each sinatra app you want to test, each of which should define its own app method that returns the corresponding app. Then you can simply include MySinatraAppHelper in the appropriate example groups where you want to test the the given app.
You can also use rspec metadata to have the module included in example groups automatically.
Have a look at my sinatra-rspec-bundler-template. Especially at the spec files. I think that's what you are trying to achieve.
It combines two separate Sinatra apps each with it's own specs.

Resources