ruby on rails - rails - ¿Por qué factory_girl no funciona transaccionalmente para mí?-las filas permanecen en la base de datos después de las pruebas
rspec factory bot (5)
Dentro de test/test_helper.rb
asegúrese de tener lo siguiente.
class ActiveSupport::TestCase
self.use_transactional_fixtures = true
#...
end
A pesar del nombre "accesorios" esto funciona también con factory_girl
.
Estoy intentando usar factory_girl para crear una fábrica de "usuario" (con RSpec), pero parece que no funciona de manera transaccional y aparentemente está fallando debido a los datos remanentes de pruebas anteriores en la base de datos de prueba.
Factory.define :user do |user|
user.name "Joe Blow"
user.email "[email protected]"
user.password ''password''
user.password_confirmation ''password''
end
@user = Factory.create(:user)
Ejecutar el primer conjunto de pruebas está bien:
spec spec/
...
Finished in 2.758806 seconds
60 examples, 0 failures, 11 pending
Todo bien y como se esperaba, sin embargo, ejecutando las pruebas nuevamente:
spec spec/
...
/Library/Ruby/Gems/1.8/gems/activerecord-2.3.8/lib/active_record/validations.rb:1102:in `save_without_dirty!'': Validation failed: Email has already been taken (ActiveRecord::RecordInvalid)
from /Library/Ruby/Gems/1.8/gems/activerecord-2.3.8/lib/active_record/dirty.rb:87:in `save_without_transactions!''
from /Library/Ruby/Gems/1.8/gems/activerecord-2.3.8/lib/active_record/transactions.rb:200:in `save!''
from /Library/Ruby/Gems/1.8/gems/activerecord-2.3.8/lib/active_record/connection_adapters/abstract/database_statements.rb:136:in `transaction''
from /Library/Ruby/Gems/1.8/gems/activerecord-2.3.8/lib/active_record/transactions.rb:182:in `transaction''
from /Library/Ruby/Gems/1.8/gems/activerecord-2.3.8/lib/active_record/transactions.rb:200:in `save!''
from /Library/Ruby/Gems/1.8/gems/activerecord-2.3.8/lib/active_record/transactions.rb:208:in `rollback_active_record_state!''
from /Library/Ruby/Gems/1.8/gems/activerecord-2.3.8/lib/active_record/transactions.rb:200:in `save!''
from /Library/Ruby/Gems/1.8/gems/factory_girl-1.2.3/lib/factory_girl/proxy/create.rb:6:in `result''
from /Library/Ruby/Gems/1.8/gems/factory_girl-1.2.3/lib/factory_girl/factory.rb:316:in `run''
from /Library/Ruby/Gems/1.8/gems/factory_girl-1.2.3/lib/factory_girl/factory.rb:260:in `create''
from /Users/petenixey/Rails_apps/resample/spec/controllers/users_controller_spec.rb:7
from /Library/Ruby/Gems/1.8/gems/rspec-1.3.0/lib/spec/example/example_group_methods.rb:183:in `module_eval''
from /Library/Ruby/Gems/1.8/gems/rspec-1.3.0/lib/spec/example/example_group_methods.rb:183:in `subclass''
from /Library/Ruby/Gems/1.8/gems/rspec-1.3.0/lib/spec/example/example_group_methods.rb:55:in `describe''
from /Library/Ruby/Gems/1.8/gems/rspec-1.3.0/lib/spec/example/example_group_factory.rb:31:in `create_example_group''
from /Library/Ruby/Gems/1.8/gems/rspec-1.3.0/lib/spec/dsl/main.rb:28:in `describe''
from /Users/petenixey/Rails_apps/resample/spec/controllers/users_controller_spec.rb:3
from /Library/Ruby/Gems/1.8/gems/activesupport-2.3.8/lib/active_support/dependencies.rb:147:in `load_without_new_constant_marking''
from /Library/Ruby/Gems/1.8/gems/activesupport-2.3.8/lib/active_support/dependencies.rb:147:in `load''
from /Library/Ruby/Gems/1.8/gems/rspec-1.3.0/lib/spec/runner/example_group_runner.rb:15:in `load_files''
from /Library/Ruby/Gems/1.8/gems/rspec-1.3.0/lib/spec/runner/example_group_runner.rb:14:in `each''
from /Library/Ruby/Gems/1.8/gems/rspec-1.3.0/lib/spec/runner/example_group_runner.rb:14:in `load_files''
from /Library/Ruby/Gems/1.8/gems/rspec-1.3.0/lib/spec/runner/options.rb:133:in `run_examples''
from /Library/Ruby/Gems/1.8/gems/rspec-1.3.0/lib/spec/runner/command_line.rb:9:in `run''
from /Library/Ruby/Gems/1.8/gems/rspec-1.3.0/bin/spec:5
from /usr/bin/spec:19:in `load''
from /usr/bin/spec:19
Arreglo de intento - use Factory.sequence
Como tengo una restricción de exclusividad en mi campo de correo electrónico, intenté solucionar el problema utilizando el método de secuencia de factory_girl:
Factory.define :user do |user|
user.name "Joe Blow"
user.sequence(:email) {|n| "joe#{n}@blow.com" }
user.password ''password''
user.password_confirmation ''password''
end
Entonces corrí
rake db:test:prepare
spec spec/
.. # running the tests once executes fine
spec spec/
.. # running them the second time produces the same set of errors as before
Los usuarios parecen permanecer en la base de datos
Si miro la base de datos /db/test.sqlite3, parece que la fila para el usuario de prueba no se está retirando de la base de datos entre las pruebas. Pensé que se suponía que estas pruebas serían transaccionales, pero no parecen ser así para mí.
Esto explicaría por qué la prueba se ejecuta correctamente la primera vez (y si borro la base de datos) pero falla la segunda vez.
¿Alguien puede explicar lo que debería cambiar para garantizar que las pruebas se realicen de forma transaccional?
En spec/spec_helper.rb
, asegúrese de tener lo siguiente
RSpec.configure do |config|
config.use_transactional_fixtures = true
end
Esto parece resolver el problema para mí.
Finalmente arreglé esto y espero poder salvar a alguien de las seis horas de depuración que me llevó a resolverlo.
Por a) tener suerte y terminar con una versión de código que funcionó yb) eliminar ambos conjuntos de códigos esto es lo que encontré:
Prueba que se ahoga
require ''spec_helper''
describe UsersController do
@user = Factory.create(:user)
end
Prueba que funciona
require ''spec_helper''
describe UsersController do
it "should make a factory models without choking" do
@user = Factory.create(:user)
end
end
La transacción se define por la declaración "should do something" do ... Si instancia la fábrica fuera de esa declaración, resulta que no es transaccional.
También puede colocarlo fuera del bloque "should should ..." siempre que esté en un bloque "before..end"
require ''spec_helper''
describe UsersController do
before(:each) do
@user = Factory.create(:user)
end
it ''should make a factory without choking'' do
puts @user.name
# prints out the correnct name for the user
end
end
Al experimentar, parece ser válido definir un usuario fuera de un bloque "debería hacer ... fin" siempre que esté en un bloque "antes ... fin". Supongo que esto solo se ejecuta en el alcance del bloque "debería hacer ... fin" y, por lo tanto, funciona bien.
[Gracias a @jdl por su sugerencia (también correcta)]
Me encontré con los mismos síntomas cuando actualicé un proyecto de Rails 3 a Rails 4. Hice una instalación de paquete, y el modo de desarrollo parecía funcionar bien, pero no obtuve el comportamiento transaccional en las pruebas. Resulta que al hacer una actualización del paquete, se solucionó el problema.
Ver la entrada de mi blog sobre la diferencia entre usar before :all
y before :each
con respecto a las transacciones: http://mwilden.blogspot.com/2010/11/beware-of-rspecs-before-all.html . En pocas palabras, before :all
no es transaccional, y los datos creados allí permanecerán después de que se ejecute la prueba.