ruby - spectroscopy - Rspec dejó ver el alcance
rspec spectroscopy (5)
Descubrí que si no pasas explícitamente el parámetro declarado por let
, estará disponible en el ejemplo compartido.
Asi que:
describe Connection do
let(:connection) { described_class.new(connection_settings) }
it_behaves_like "any connection"
end
la conexión estará disponible en las especificaciones de ejemplo compartidas
Creo que tengo un problema con rspec let y scoping. Puedo usar los métodos definidos con let in examples (los bloques "it"), pero no afuera (el bloque describe donde hice el let).
5 describe Connection do
8 let(:connection) { described_class.new(connection_settings) }
9
10 it_behaves_like "any connection", connection
24 end
Cuando intento ejecutar esta especificación, obtengo el error:
connection_spec.rb: 10: variable local indefinida o método `connection ''para Class: 0xae8e5b8 (NameError)
¿Cómo puedo pasar el parámetro de conexión a it_behaves_like?
Encontré lo que funciona para mí:
describe Connection do
it_behaves_like "any connection", new.connection
# new.connection: because we''re in the class context
# and let creates method in the instance context,
# instantiate a instance of whatever we''re in
end
Esto funciona para mí:
describe "numbers" do
shared_examples "a number" do |a_number|
let(:another_number) {
10
}
it "can be added to" do
(a_number + another_number).should be > a_number
end
it "can be subtracted from" do
(a_number - another_number).should be < a_number
end
end
describe "77" do
it_should_behave_like "a number", 77
end
describe "2" do
it_should_behave_like "a number", 2
end
end
let () se supone que tiene un alcance para los bloques de ejemplo e inutilizable en otro lugar. En realidad, no usa let () como parámetros. La razón por la que no funciona con it_behaves_like como parámetro tiene que ver con cómo se define let (). Cada grupo de ejemplo en Rspec define una clase personalizada. let () define un método de instancia en esa clase. Sin embargo, cuando llamas it_behaves_like en esa clase personalizada, está llamando al nivel de clase en lugar de desde una instancia.
He usado let () de esta manera:
shared_examples_for ''any connection'' do
it ''should have valid connection'' do
connection.valid?
end
end
describe Connection do
let(:connection) { Connection.new(settings) }
let(:settings) { { :blah => :foo } }
it_behaves_like ''any connection''
end
He hecho algo similar a la respuesta de bcobb, aunque rara vez uso shared_examples:
module SpecHelpers
module Connection
extend ActiveSupport::Concern
included do
let(:connection) { raise "You must override ''connection''" }
end
module ClassMethods
def expects_valid_connection
it "should be a valid connection" do
connection.should be_valid
end
end
end
end
end
describe Connection do
include SpecHelpers::Connection
let(:connection) { Connection.new }
expects_valid_connection
end
La definición de esos ejemplos compartidos es más detallada que usar ejemplos compartidos. Creo que encuentro que "it_behave_like" es más incómodo que extender Rspec directamente.
Obviamente, puede agregar argumentos a .expects_valid_connections
Escribí esto para ayudar a la clase rspec de un amigo: http://ruby-lambda.blogspot.com/2011/02/agile-rspec-with-let.html ...
Redacted - completamente añicos en mi primera solución. Ho-Sheng Hsiao dio una gran explicación de por qué.
Puedes darle it_behaves_like
a block como ese:
describe Connection do
it_behaves_like "any connection" do
let(:connection) { described_class.new(connection_settings) }
end
end