Subsecciones

Pruebas/Testing


Pruebas Unitarias

  1. Los fuentes de este ejemplo están en https://github.com/crguezl/rack-unit-test
  2. Fuentes en GitHub de Rack::Test: https://github.com/brynary/rack-test

[~/rack/rack-unit-test(master)]$ cat rack_hello_world.rb 
# my_app.rb
#
require 'rack'

class MyApp
  def call env
    [200, {"Content-Type" => "text/html"}, ["Hello"]] 
  end
end

[~/rack/rack-unit-test(master)]$ cat test_hello_world.rb 
require "test/unit"
require "rack/test"
require './rack_hello_world'

class AppTest < Test::Unit::TestCase
  include Rack::Test::Methods

  def app
    Rack::Builder.new do
      run MyApp.new
    end.to_app
  end

  def test_index
    get "/"
    #puts last_response.inspect
    assert last_response.ok?
  end

  def test_body
    get "/"
    assert_equal last_response.body,  'Hello', "body must be hello"
  end
end
  1. The Rack::Test::Methods module serves as the primary integration point for using Rack::Test in a testing environment.

    It depends on an app method being defined in the same context,

      def app
        Rack::Builder.new do
          run MyApp.new
        end.to_app
      end
    

    and provides the Rack::Test API methods (see Rack::Test::Session for their documentation).

  2. The get method issue a GET request for the given URI. Stores the issues request object in #last_request and the app's response in #last_response (whose class is Rack::MockResponse) .

    Yield #last_response to a block if given.

      def test_index
        get "/"
        assert last_response.ok?
      end
    

  3. Otros métodos que se pueden usar son:
    1. (Object) basic_authorize(username, password) (also: #authorize) Set the username and password for HTTP Basic authorization, to be included in subsequent requests in the HTTP_AUTHORIZATION header.
    2. (Object) delete(uri, params = {}, env = {}, &block) Issue a DELETE request for the given URI.
    3. (Object) digest_authorize(username, password) Set the username and password for HTTP Digest authorization, to be included in subsequent requests in the HTTP_AUTHORIZATION header.
    4. (Object) env(name, value) Set an env var to be included on all subsequent requests through the session.
    5. (Object) follow_redirect! Rack::Test will not follow any redirects automatically.
    6. (Object) get(uri, params = {}, env = {}, &block) Issue a GET request for the given URI with the given params and Rack environment.
    7. (Object) head(uri, params = {}, env = {}, &block) Issue a HEAD request for the given URI.
    8. (Object) header(name, value) Set a header to be included on all subsequent requests through the session.
    9. (Session) initialize(mock_session) constructor Creates a Rack::Test::Session for a given Rack app or Rack::MockSession.
    10. (Object) options(uri, params = {}, env = {}, &block) Issue an OPTIONS request for the given URI.
    11. (Object) patch(uri, params = {}, env = {}, &block) Issue a PATCH request for the given URI.
    12. (Object) post(uri, params = {}, env = {}, &block) Issue a POST request for the given URI.
    13. (Object) put(uri, params = {}, env = {}, &block) Issue a PUT request for the given URI.
    14. (Object) request(uri, env = {}, &block) Issue a request to the Rack app for the given URI and optional Rack environment.

  4. The #last_response object has methods:
              =~(other) body() empty?() match(other)
    
    and attributes:
    errors          [RW]
    original_headers[R]
    Headers
    
  5. Si se usan middleware adicionales es necesario especificarlo en app:
      def app 
        Rack::Builder.new do
          use(Rack::Session::Cookie, {:key => 'rack session',·
                                      #:domain => 'localhost',
                                      #:path => '/', #:expire_after => 2592000,·
                                      :secret => 'change_me'})
          run RockPaperScissors::App.new
        end.to_app
      end
    
  6. El método last_response.body returns the last response received in the session. Raises an error if no requests have been sent yet.

[~/rack/rack-unit-test(master)]$ cat Rakefile 
task :default => :test
desc "run the tests"
task :test do
  sh "ruby test_hello_world.rb"
end

[~/rack/rack-unit-test(master)]$ cat Gemfile
source 'https://rubygems.org'

gem 'rack'
gem 'rack-test'

[~/rack/rack-unit-test(master)]$ rake
ruby test_hello_world.rb
Run options: 

# Running tests:

..

Finished tests in 0.015253s, 131.1217 tests/s, 131.1217 assertions/s.

2 tests, 2 assertions, 0 failures, 0 errors, 0 skips


Rspec con Rack

Véase

  1. Los fuentes de este ejemplo están en: https://github.com/crguezl/rack-rspec
  2. Using RSpec with Rack en Youtube por Mike Bethany
  3. Documentación en rubydoc.info del módulo Rack::MockSession http://rdoc.info/github/brynary/rack-test/master/Rack/MockSession
  4. Código fuente en lib/rack/mock.rb
  5. Documentación en rubydoc.info del módulo Rack::Test::Methods: http://rdoc.info/github/brynary/rack-test/master/Rack/Test/Methods
  6. Documentación de Rack::Test::Session
  7. webmock gem
  8. Class: Rack::MockRequest documentation
  9. How to Test Sinatra-Based Web Services by Harlow Ward, March 17, 2013 Webmock Written by thoughtbot Harlow Ward March 17, 2013

Jerarquía

[~/rack/rack-rspec(master)]$ tree
.
|--- Gemfile
|--- Gemfile.lock
|--- README
|--- Rakefile
|--- lib
|   |--- rsack
|   |   `--- server.rb
|   `--- rsack.rb
`--- spec
    |--- rsack
    |   `--- server_spec.rb
    `--- spec_helper.rb

4 directories, 8 files

lib/rsack.rb

[~/rack/rack-rspec(master)]$ cat lib/rsack.rb 
require 'rack'
require 'rsack/server'

lib/rsack/server.rb

[~/rack/rack-rspec(master)]$ cat lib/rsack/server.rb 
module Rsack
  class Server
    def call(env)
      #["200", {}, "hello"]
      response = Rack::Response.new
      response.write("Hello world!")
      response.finish
    end
  end
end

spec/rsack/server_spec.rb

[~/rack/rack-rspec(master)]$ cat spec/rsack/server_spec.rb 
require 'spec_helper'

describe Rsack::Server do

  #let(:server) { Rack::MockRequest.new(Rsack::Server.new) }
  def server
    Rack::MockRequest.new(Rsack::Server.new) 
  end

  context '/' do
    it "should return a 200 code" do
      response = server.get('/')
      response.status.should == 200
    end
  end
end
Rack::MockRequest helps testing your Rack application without actually using HTTP.
    Rack::MockRequest.new(Rsack::Server.new)
After performing a request on a URL response = server.get('/') with get/post/put/patch/delete, it returns a MockResponse with useful helper methods for effective testing (Véase el código de MockResponse en Github en el fichero lib/rack/mock.rb).

Un objeto MockResponse dispone de los métodos:

=~   []   match   new
y de los atributos:
body   [R]   Body
errors   [RW]    Errors
headers  [R]   Headers
original_headers   [R]   Headers
status   [R]   Status

Si se usan middleware adicionales es necesario especificarlo en server. Por ejemplo:

 Rack::MockRequest.new(Rack::Session::Cookie.new(RockPaperScissors::App.new, 
                                                 :secret =>'cookie'))

spec/spec_helper.rb

[~/rack/rack-rspec(master)]$ cat spec/spec_helper.rb 
$:.unshift File.expand_path(File.dirname(__FILE__)+'../lib')
$:.unshift File.dirname(__FILE__)

#puts $:.inspect

require 'rspec'
require 'rack'

require 'rsack'

Rakefile

[~/rack/rack-rspec(master)]$ cat Rakefile 
desc "run rspec tests"
task :default do
  sh "rspec spec/rsack/server_spec.rb"
end

Gemfile

[~/rack/rack-rspec(master)]$ cat Gemfile
# A sample Gemfile
source "https://rubygems.org"

gem 'rack'

group :development, :test do
  gem 'rspec'
end

Casiano Rodríguez León
2015-01-25