Search code examples
rubytestingrspecruby-grapegoliath

Testing Goliath + Grape with Rspec


I'm trying to test a Goliath + Grape app like the following:

require 'em-synchrony/em-mongo'
require 'yajl/json_gem'
require 'goliath'
require 'grape'

class API < Grape::API
  version 'v1', :using => :path
  format :json

  resource 'categories' do
    # http://0.0.0.0:9000/v1/categories/
    get "/" do
      coll = env.mongo.collection('categories') #Connection Pool from Goliath ENV
      coll.find({})
    end
  end
end

class App < Goliath::API
  def response(env)
    API.call(env)
  end
end

these two classes are in a single file called app.rb. Running ruby ./app.rb -sv start a goliath app on http://0.0.0.0:9000/v1/categories/ which is perfectly working, but needs rspec before making more complex endpoints. Anyway running the spec I get

undefined local variable or method `app'

which I'm unable to get rid of:

$ bundle exec rspec spec/api_spec.rb
FFFF

Failures:

  1) App App GET /v1/categories get several categories of repositories by name
     Failure/Error: get "/v1/categories"
     NameError:
       undefined local variable or method `app' for #<RSpec::Core::ExampleGroup::Nested_1::Nested_1::Nested_1:0x993eec4>
     # ./spec/api_spec.rb:9:in `block (4 levels) in <top (required)>'

the api_spec looks like the following:

require 'spec_helper'

describe App do
  include Rack::Test::Methods

  describe App do
    describe 'GET /v1/categories' do
      it 'get several categories of repositories by name' do
        get "/v1/categories"
        last_response.status.should == 200
        JSON.parse(last_response.body)["name"].should == "Ruby Web Frameworks"
      end
    end
  end
end

UPDATE :

adding app method to spec/api_spec.rb :

def app
    App
end

rise another kind of error :

  1) App App GET /v1/categories get several categories of repositories by name
     Failure/Error: get "/v1/categories"
     NoMethodError:
       undefined method `call' for App:Class
     # ./spec/api_spec.rb:13:in `block (4 levels) in <top (required)>'

UPDATE

adding API class called from app method within spec/api_spec.rb :

def app
  API
end

get undefined methodmongo'` :

Failures:

  1) App App GET /v1/categories get several categories of repositories by name
     Failure/Error: get "/v1/categories"
     NoMethodError:
       undefined method `mongo' for #<Hash:0xad5ea58>
     # ./app.rb:14:in `block (2 levels) in <class:API>'
     # ./spec/api_spec.rb:13:in `block (4 levels) in <top (required)>'

see coll = env.mongo.collection('categories') inside API class


Solution

  • I finally have been able to make it working using goliath test_helper. This is for tracking purpose, hoping it can help someone else.

    In spec/spec_helper.rb add goliath test helper and all dependencies. In my case :

    require 'em-synchrony/em-http'
    require 'goliath/test_helper'
    require 'yajl/json_gem'
    
    Goliath.env = :test
    
    RSpec.configure do |c|
      c.include Goliath::TestHelper, :example_group => {
        :file_path => /spec\//
      }
    end
    

    in spec/app_spec.rb

    require 'spec_helper'
    require File.join(File.dirname(__FILE__), '../', 'app')
    
    describe App do
      def config_file
        File.expand_path(File.join(File.dirname(__FILE__), '..', 'config', 'app.rb'))
      end
    
      let(:api_options) { { :config => config_file } }
    
      it 'renders ' do
        with_api(App, api_options) do
          get_request(:path => '/v1/categories') do |c|
            resp = JSON.parse(c.response)
            categories = resp.map{|r|r['name']}
            categories.to_s.should =~ /Ruby Web Frameworks/
          end
        end
      end
    end
    

    Goliath application dir tree, looks like :

    lsoave@ubuntu:~/rails/github/GGM$ ls -l 
    total 48
    -rw-rw-r-- 1 lsoave lsoave  483 Feb 25 23:06 app.rb
    -rw-rw-r-- 1 lsoave lsoave 6321 Feb 25 23:06 categories.json
    drwxrwxr-x 2 lsoave lsoave 4096 Feb 25 23:06 config
    -rw-rw-r-- 1 lsoave lsoave  381 Feb 25 23:06 Gemfile
    -rw-rw-r-- 1 lsoave lsoave 2293 Feb 25 23:06 Gemfile.lock
    -rw-rw-r-- 1 lsoave lsoave   59 Feb 21 20:37 Procfile
    -rw-rw-r-- 1 lsoave lsoave  123 Feb 25 23:06 Rakefile
    -rw-rw-r-- 1 lsoave lsoave 7003 Feb 21 20:37 README.md
    -rw-rw-r-- 1 lsoave lsoave  238 Feb 25 23:06 README.mongoimport
    drwxrwxr-x 2 lsoave lsoave 4096 Feb 25 23:23 spec
    lsoave@ubuntu:~/rails/github/GGM$ 
    

    where config and spec subdirs look like :

    lsoave@ubuntu:~/rails/github/GGM$ ls -l config spec
    config:
    total 4
    -rw-rw-r-- 1 lsoave lsoave 870 Feb 25 23:06 app.rb
    
    spec:
    total 11
    -rw-rw-r-- 1 lsoave lsoave  777 Feb 25 23:06 app_spec.rb
    -rw-rw-r-- 1 lsoave lsoave  218 Feb 25 23:06 spec_helper.rb
    lsoave@ubuntu:~/rails/github/GGM$ 
    

    the main goliath app is the same as my first post :

    require 'em-synchrony/em-mongo'
    require 'yajl/json_gem'
    require 'goliath'
    require 'grape'
    
    class API < Grape::API
      version 'v1', :using => :path
      format :json
    
      resource 'categories' do
        # http://0.0.0.0:9000/v1/categories/
        get "/" do
          coll = env.mongo.collection('categories') #Connection Pool from Goliath ENV
          coll.find({})
        end
      end
    end
    
    class App < Goliath::API
      def response(env)
        API.call(env)
      end
    end
    

    preatty simple in the end. If you want to go deeper have a look at https://github.com/lgs/GGM.