Configura RSpec para probar una gema (no Rails)

154

Es bastante fácil con el generador adicional de rspec-rails configurar RSpec para probar una aplicación Rails. Pero, ¿qué hay de agregar RSpec para probar una gema en desarrollo? No estoy usando joyero o tales herramientas. Acabo de usar Bundler ( bundle gem my_gem) para configurar la estructura de la nueva gema y editar manualmente * .gemspec. También agregué s.add_development_dependency "rspec", ">= 2.0.0"a gemspec e hice un bundle install.

¿Hay algún tutorial agradable que hacer a continuación para que RSpec funcione?

Zardoz
fuente
Supongo que tengo que escribir uno :-) ... Al menos hay dos gemas que ya lo integran muy bien: act-as-taggable-on y actions_as_geocodable.
Zardoz

Respuestas:

255

He actualizado esta respuesta para que coincida con las mejores prácticas actuales:

Bundler apoya el desarrollo de gemas perfectamente. Si está creando una gema, lo único que necesita tener en su Gemfile es lo siguiente:

source "https://rubygems.org"
gemspec

Esto le dice a Bundler que busque dentro de su archivo gemspec las dependencias cuando ejecuta bundle install.

A continuación, asegúrese de que RSpec sea una dependencia de desarrollo de su gema. Edite el gemspec para que se lea:

spec.add_development_dependency "rspec"

A continuación, cree spec/spec_helper.rby agregue algo como:

require 'bundler/setup'
Bundler.setup

require 'your_gem_name' # and any other gems you need

RSpec.configure do |config|
  # some (optional) config here
end

Las primeras dos líneas le dicen a Bundler que cargue solo las gemas dentro de su gemspec. Cuando instala su propia gema en su propia máquina, esto obligará a sus especificaciones a usar su código actual, no la versión que ha instalado por separado.

Cree una especificación, por ejemplo spec/foobar_spec.rb:

require 'spec_helper'
describe Foobar do
  pending "write it"
end

Opcional: agregue un .rspecarchivo para las opciones predeterminadas y póngalo en la ruta raíz de su gema:

--color
--format documentation

Finalmente: ejecuta las especificaciones:

$ rspec spec/foobar_spec.rb
iain
fuente
75
Para ser justos, debería invocar el comando init de RSpec para generar los archivos de esqueleto de especificaciones en lugar de tener que escribirlos manualmente. Esto garantizaría la compatibilidad con la versión de RSpec que está utilizando: rspec --init
Attila Györffy
12
rspec --initno estaba disponible cuando escribí esto, ¡pero buen punto!
iain
En realidad, encontré que la mejor manera de hacer los requisitos en el asistente de especificaciones es esta: requiere 'rubygems' requiere 'bundler / setup' Bundler.require (: default
,:
¿En qué se diferencian exactamente las tres líneas de código de @ mkon de las tres líneas de código de iain?
Nakilon
1
Las líneas de @mkon requerirán todas las gemas en los grupos de desarrollo y prueba, mientras que mi enfoque es requerir cada gema manualmente. Dado que necesita requerir cada gema para hacer gemas, creo que es el enfoque mejor / más claro, aunque podría ser un poco más trabajo.
iain
53

¡La solución de Iain anterior funciona muy bien!

Si también quieres un Rakefile, esto es todo lo que necesitas:

require 'rspec/core/rake_task'

RSpec::Core::RakeTask.new(:spec)

# If you want to make this the default task
task default: :spec

Consulte el RDoc para RakeTask para ver varias opciones que opcionalmente puede pasar a la definición de tarea.

Mirko Froehlich
fuente
26

Puedes generar tu nueva gema con rspec ejecutando bundler gem --test=rspec my_gem. ¡Sin configuración adicional!

Siempre me olvido de esto. Se implementa aquí: https://github.com/bundler/bundler/blob/33d2f67d56fe8bf00b0189c26125d27527ef1516/lib/bundler/cli/gem.rb#L36

StevenNunez
fuente
1
¡Ordenado! Sin embargo, creo que su nombre de gema debe especificarse con guiones bajos en lugar de mayúsculas y minúsculas. De lo contrario, Bundler crea archivos con letras mayúsculas (Bundler 1.7.4)
Malte
Bundler se quejó --test=rspec, pero todavía me preguntó si quería usar Rspec cuando corrí bundler gem my_gem.
Nicolas Mattia
7

Aquí hay una manera barata y fácil (aunque no se recomienda oficialmente):

Haga un directorio en la raíz de su gema llamado spec, ponga sus especificaciones allí. Probablemente ya tenga instalado rspec, pero si no lo tiene, simplemente haga una gem install rspecy olvide Gemfiles y bundler.

A continuación, hará una especificación y deberá decirle dónde está su aplicación, dónde están sus archivos e incluir el archivo que desea probar (junto con las dependencias que tenga):

# spec/awesome_gem/awesome.rb
APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..', '..'))
$: << File.join(APP_ROOT, 'lib/awesome_gem') # so rspec knows where your file could be
require 'some_file_in_the_above_dir' # this loads the class you want to test

describe AwesomeGem::Awesome do
  before do
    @dog = AwesomeGem::Awesome.new(name: 'woofer!')
  end
  it 'should have a name' do
    @dog.name.should eq 'woofer!'
  end
  context '#lick_things' do
    it 'should return the dog\'s name in a string' do
      @dog.lick_things.should include 'woofer!:'
    end
  end
end

Abra la Terminal y ejecute rspec:

~/awesome_gem $ rspec
..

Finished in 0.56 seconds
2 examples, 0 failures

Si quieres algunas .rspecopciones amorosas, ve a hacer un .rspecarchivo y colócalo en la ruta raíz de tu gema. El mío se ve así:

# .rspec
--format documentation --color --debug --fail-fast

¡Fácil, rápido, ordenado!

Me gusta esto porque no tiene que agregar ninguna dependencia a su proyecto en absoluto, y todo sigue siendo muy rápido. bundle execralentiza un poco las cosas, que es lo que tendría que hacer para asegurarse de que usa la misma versión de rspec todo el tiempo. Los 0,56 segundos que tardó en ejecutar dos pruebas estaban ocupados en un 99% cuando mi computadora tardó en cargar rspec. Ejecutar cientos de especificaciones debería ser extremadamente rápido. El único problema con el que podría toparse es que si cambia las versiones de rspec y la nueva versión no es compatible con alguna de las funciones que utilizó en su prueba, es posible que deba volver a escribir algunas pruebas.

Esto es bueno si está haciendo especificaciones únicas o tiene alguna buena razón para NO incluir rspec en su gemspec, sin embargo, no es muy bueno para permitir compartir o hacer cumplir la compatibilidad.

wulftone
fuente
¿Hay alguna manera de no poner AwesomeGem :: antes de los nombres de clase cada vez que se refiere a un objeto de prueba? O cuando creas una nueva prueba como en tu ejemplo.
Misha Slyusarev
1
Claro, puede configurar su nombre de clase igual a algo más corto, Thing = AwesomeGem::Awesomeo puede hacer la prueba dentro de un módulo, comomodule AwesomeGem; it 'stuff' do; Awesome.new ... end; end
wulftone