Sinatra testing

Sinatra testing con Rack::Test

Todos los ejemplos a continuación asumen que se está utilizando Test::Unit con la idea de ser lo más general posible, luego revisaremos otras posibilidades.

Ejemplo hola_mundo.rb

1require 'sinatra'
2
3get '/' do
4  "Hola Mundo #{params[:nobre]}".strip
5end

Usando el Mixin Rack::Test::Methods

El módulo Rack::Test::Methods incluye una variedad de métodos ayudantes para simular solicitudes a una aplicación y para hacer aserciones sobre las expectativas acerca de al respuesta. Típicamente se incluye este módulo directamente dentro del contexto de prueba y pone disponible unos cuantos métodos ayudantes y atributos.

El siguiente es un ejemplo simple que asegura que la aplicación hola mundo funciona apropiadamente.

hola_mundo_tc-1.rb

 1require 'hola_mundo'
 2require 'test/unit'
 3require 'rack/test'
 4
 5ENV['RACK_ENV'] = 'test'
 6
 7class HolaMundoTest < Test::Unit::TestCase
 8  include Rack::Test::Methods
 9
10  def app
11    Sinatra::Application
12  end
13
14  def test_dice_hola_mundo
15    get '/'
16    assert last_response.ok?
17    assert_equal 'Hola Mundo', last_response.body
18  end
19
20  def test_dice_hola_mundo_a_una_persona
21    get '/', :nombre => 'Guillermo'
22    assert last_response.body.include?('Guillermo')
23  end
24end

Primera corrida de nuestras pruebas:

$ ruby hola_mundo_tc-1.rb 
Loaded suite hola_mundo_tc
Started
..
Finished in 0.038352 seconds.

2 tests, 3 assertions, 0 failures, 0 errors

Usando Rack::Test sin el Mixin

Tal vez por alguna razón usted no desee incluir Rack::Test::Methods en sus clases. *Rack::Test soporta dicho estilo de pruebas también, abajo un ejemplo sin el uso de Mixin.

hola_mundo_tc-1.rb

 1require 'hola_mundo'
 2require 'test/unit'
 3require 'rack/test'
 4
 5set :environment, :test
 6
 7class HolaMundoTest < Test::Unit::TestCase
 8
 9  def test_dice_hola_mundo
10    browser = Rack::Test::Session.new(Rack::MockSession.new(Sinatra::Application))
11    browser.get '/'
12    assert browser.last_response.ok?
13    assert_equal 'Hola Mundo', browser.last_response.body
14  end
15
16  def test_dice_hola_mundo_a_una_persona
17    browser = Rack::Test::Session.new(Rack::MockSession.new(Sinatra::Application))
18    browser.get '/', :nombre => 'Guillermo'
19    assert browser.last_response.body.include?('Guillermo')
20  end
21end

Corrida de las pruebas:

$ ruby hola_mundo_tc-2.rb 
Loaded suite hola_mundo_tc-2
Started
..
Finished in 0.012911 seconds.

2 tests, 3 assertions, 0 failures, 0 errors

Métodos de solicitud falsos Rack::Test (Mocks)

Los métodos get, put, post, delete y head simulan las solicitudes de tipo correspondiente hacia la aplicación. Las pruebas típicamente comienzan con una llamada a uno de estos métodos seguidos de uno o más aserciones sobre la respuesta resultante.

Todos los métodos de solicitud falsos tienen la misma firma de argumentos:

get '/path', params={}, rack_env={}

  • /path es la ruta/path solicitada y opcionalmente puede incluir una cadena consulta (query string).
  • params es un Hash de parámetros query/post, un cuerpo de solicitud String, o nil.
  • rack_env es un Hash de valores de entorno de Rack. Esto se puede usar para establecer encabezados en la solicitud y/o otras informaciones relacionadas a la solicitud tal como datos de sesión. Véa Rack SPEC para más información sobre los posibles pares llave/valor.

Aserciones y expectaticas acerca de la respuesta

Una vez que el método de solicitud ha sido invocado, los siguientes atributos están disponibles para ejecutar aserciones:

  • app - La calse aplicación Sinatra que manejó la solicitud falsa.
  • last_request - El Rack::MockRequest utilizado para hacer la solicitud.
  • last_response - Una instancia Rack::MockResponse con información de la respuesta generada por la aplicación.

Las aserciones son típicamente hechas usando el objeto last_response. Considere los ejemplos:

1def test_dice_hola_mundo
2  get '/'
3  assert last_response.ok?
4  assert_equal 'Hola Mundo'.length.to_s, last_response.headers['Content-Length']
5  assert_equal 'Hola Mundo', last_response.body
6end

Configuración de la prueba

Los métodos de solicitud falsa Rack::Test envían solicitudes al valor de retorno de un método llamado app.

Si usted está probando una aplicación modular que tiene múltiples subclases Sinatra::Base, simplemente configure el método app para que devuelva su clase en particular.

1  def app
2    MiAppSinatra
3  end

Si está usando el estilo clásico de aplicación Sinatra, entonces debe devolver una instancia de Sinatra::Application.

1  def app
2    Sinatra::Application
3  end

Hacer que Rack::Test esté disponible para todos los casos de prueba

Si desea que los métodos Rack::Test estén disponible en todos los casos de prueba sin tener que incluirlo cada vez, puede incluir el módulo Rack::Test en la clase Test::Unit::TestCase :

1require 'test/unit'
2require 'rack/test'
3
4class Test::Unit::TestCase
5  include Rack::Test::Methods
6end

Ahora todas las subclases de TestCase tendrán automáticamente disponible Rack::Test.

Otros marcos de prueba

A partir de Sinatra 1.0 ya no se proveen ayudantes específicos a ningún marco de pruebas.

RSpec, ejemplo

Sinatra puede ser probado bajo RSpec. El módulo Rack::Test debería estar incluído dentro del bloque de descripción:

 1require 'hola_mundo'  # <-- su app sinatra
 2require 'spec'
 3require 'rack/test'
 4
 5set :environment, :test
 6
 7describe 'La App HolaMundo' do
 8  include Rack::Test::Methods
 9
10  def app
11    Sinatra::Application
12  end
13
14  it "dice hola" do
15    get '/'
16    last_response.should be_ok
17    last_response.body.should == 'Hola Mundo'
18  end
19end

Haga que Rack::Test esté disponible en todos los contextos spec incluyendolo via RSpec:

1require 'spec'
2require 'rack/test'
3
4RSpec.configure do |conf|
5  conf.include Rack::Test::Methods
6end

Bacon, ejemplo

El hacer pruebas con Bacon es similar a hacerlo con test/unit y RSpec:

 1require 'hola_mundo'  # <-- su app sinatra
 2require 'bacon'
 3require 'rack/test'
 4
 5set :environment, :test
 6
 7describe 'La App HolaMundo' do
 8  include Rack::Test::Methods
 9
10  def app
11    Sinatra::Application
12  end
13
14  it "dice hola" do
15    get '/'
16    last_response.should.be.ok
17    last_response.body.should.equal 'Hola Mundo'
18  end
19end

Haga que Rack::Test esté disponible en todos los contextos sepc incluyéndolo en Bacon::Context:

1class Bacon::Context
2  include Rack::Test::Methods
3end

Test::Spec, ejemplo

El módulo Rack::Test debe incluirse dentro del contexto del bloque descriptivo:

 1require 'hola_mundo'  # <-- su app sinatra
 2require 'test/spec'
 3require 'rack/test'
 4
 5set :environment, :test
 6
 7describe 'La App HolaMundo' do
 8  include Rack::Test::Methods
 9
10  def app
11    Sinatra::Application
12  end
13
14  it "dice hola" do
15    get '/'
16    last_response.should.be.ok
17    last_response.body.should.equal 'Hola Mundo'
18  end
19end

Haga que Rack::Test este disponible en todos los contextos spec incluyéndolo en Test::Unit::TestCase:

1require 'test/spec'
2require 'rack/test'
3
4Test::Unit::TestCase.send :include, Rack::Test::Methods

Webrat, ejemplo

En el wiki de Webrat encontrará más ejemplos.

 1require 'hola_mundo'  # <-- su app sinatra
 2require 'rack/test'
 3require 'test/unit'
 4
 5Webrat.configure do |config|
 6  config.mode = :rack
 7end
 8
 9class HelloWorldTest < Test::Unit::TestCase
10  include Rack::Test::Methods
11  include Webrat::Methods
12  include Webrat::Matchers
13
14  def app
15    Sinatra::Application.new
16  end
17
18  def test_funciona
19    visit '/'
20    assert_contain('Hola Mundo')
21  end
22end

Capybara, ejemplo

Capybara utilizará Rack::Test por omisión. Puede utilizar otro driver como Selenium ajustando default_driver.

 1require 'hola_mundo'  # <-- su app sinatra
 2require 'capybara'
 3require 'capybara/dsl'
 4require 'test/unit'
 5
 6class HelloWorldTest < Test::Unit::TestCase
 7  include Capybara
 8  # Capybara.default_driver = :selenium # <-- uso del driver Selenium
 9
10  def setup
11    Capybara.app = Sinatra::Application.new
12  end
13
14  def test_funciona
15    visit '/'
16    assert page.has_content?('Hola Mundo')
17  end
18end