¿Cómo preparo las bases de datos de prueba para las pruebas rspec de Rails sin ejecutar la especificación de rake?

83

Después de una resolución de problemas significativa, descubrí que necesitaba ejecutar rake specuna vez (puedo abortar con control-c) antes de poder ejecutar rspec directamente (por ejemplo, en un subconjunto de nuestras especificaciones). Estamos ejecutando Rails 3.0.7 y RSpec 2.5.0.

Claramente, rake está ejecutando algunas tareas / código de configuración de base de datos importantes (tenemos código personalizado en los rieles de nivel raíz Rakefile y posiblemente en otros lugares).

¿Cómo puedo ejecutar el código / tareas de configuración de la base de datos de prueba de rake sin ejecutar rake spec?

Además de poder ejecutar rspec en un subconjunto de archivos, estoy usando specjour para difundir nuestras especificaciones en varios núcleos (todavía no he tenido éxito al difundirlas en la LAN), pero veo el mismo comportamiento que para ejecutar rspec directamente: necesito ejecutar rake specen cada base de datos de prueba (asumiendo dos núcleos) antes de que funcione specjour:

rake spec TEST_ENV_NUMBER=1
control-c (after tests start)
rake spec TEST_ENV_NUMBER=2
control-c (after tests start)
specjour

Nota: mi config / database.yml tiene esta entrada para prueba (como es común para las gemas de prueba paralelas):

test:
  adapter: postgresql
  encoding: unicode
  database: test<%=ENV['TEST_ENV_NUMBER']%>
  username: user
  password:

Paralelo_tests parece configurar sus bases de datos correctamente, pero muchas de nuestras especificaciones fallan.

También debo mencionar que la ejecución specjour preparehace que Postgres registre errores que no pueden encontrar las bases de datos, pero las crea (sin tablas). En una ejecución posterior, no se registran errores, pero tampoco se crean tablas. Es posible que todo mi problema sea simplemente un error prepare, así que lo informé en github.

Creo que puedo ejecutar código arbitrario en cada base de datos de prueba specjour configurando Specjour::Configuration.prepare.specjour / hooks.rb, por lo que si hay tareas de rastrillo u otro código que necesito ejecutar, puede funcionar allí.

gerry3
fuente

Respuestas:

14

Tuve un problema similar al configurar el sistema CI en el trabajo, así que gradualmente creé un sistema para manejar esto. Puede que no sea la mejor solución, pero me funciona en mi situación y siempre estoy buscando mejores formas de hacer las cosas.

Tengo una base de datos de prueba que necesitaba configurar, pero también necesitaba cargar datos sembrados para que nuestras pruebas funcionen.

Lo básico para solucionar problemas de tareas de rastrillo es ejecutar rastrillo con la opción --trace para ver qué está sucediendo debajo del capó. Cuando hice esto, descubrí que ejecutar la especificación de rake hacía una serie de cosas que podía replicar (o modificar como me pareciera) en una tarea de rake personalizada.

He aquí un ejemplo de lo que hacemos.

desc "Setup test database - drops, loads schema, migrates and seeds the test db"
task :test_db_setup => [:pre_reqs] do
  Rails.env = ENV['RAILS_ENV'] = 'test'
  Rake::Task['db:drop'].invoke
  Rake::Task['db:create'].invoke
  result = capture_stdout { Rake::Task['db:schema:load'].invoke }
  File.open(File.join(ENV['CC_BUILD_ARTIFACTS'] || 'log', 'schema-load.log'), 'w') { |f| f.write(result) }
  Rake::Task['db:seed:load'].invoke
  ActiveRecord::Base.establish_connection
  Rake::Task['db:migrate'].invoke
end

Este es solo un ejemplo, y específico para nuestra situación, por lo que deberá averiguar qué se debe hacer para obtener la configuración de su base de datos de prueba, pero es bastante fácil de determinar usando la opción --trace de rake.

Además, si encuentra que la configuración de la prueba está tardando demasiado (como sucede en nuestro caso), también puede volcar la base de datos en formato .sql y hacer que la base de datos de prueba la canalice directamente a mysql para cargarla. De esa manera ahorramos varios minutos en la configuración de la base de datos de prueba. No muestro eso aquí porque complica sustancialmente las cosas: debe generarse correctamente sin volverse obsoleto, etc.

HTH

edk750
fuente
Sí, he ejecutado rake spec con --trace e intenté replicar algunas de sus tareas en mi gancho de preparación de specjour, pero aún no ha funcionado. Potencialmente, podría escribir una tarea de rake completamente separada para configurar las cosas, pero ese es otro paso que esperaba evitar.
gerry3
169

Recomendaría eliminar su base de datos de prueba, luego volver a crearla y migrar:

bundle exec rake db:drop RAILS_ENV=test
bundle exec rake db:create RAILS_ENV=test
bundle exec rake db:schema:load RAILS_ENV=test

Después de estos pasos, puede ejecutar sus especificaciones:

bundle exec rspec spec

gerry3 señaló que:

Una solución más simple es simplemente ejecutar rake db:test:prepare

Sin embargo, si está utilizando PostgreSQL, esto no funcionará porque el entorno de rieles se carga, lo que abre una conexión a la base de datos. Esto hace que la preparellamada falle, porque la base de datos no se puede quitar. Cosa complicada.

leviatán
fuente
47
Una solución más sencilla es simplemente ejecutar rake db:test:prepare.
gerry3
7
No tengo problemas para ejecutar rake db:test:preparePostgres. Debes estar viendo tu problema por alguna otra razón.
gerry3
Si db: test: prepare no funciona, al menos puede poner los comandos en línea para ahorrar algo de escritura:RAILS_ENV=test bundle exec rake db:drop db:create db:schema:load
fun whilelost
11
Parece que rake db:test:prepareestá obsoleto en Rails 4.
markquezada
8
Puede encadenar tareas de rastrillo como esta:bundle exec rake db:drop db:create db:schema:load RAILS_ENV=test
davegson
14

Todas las soluciones proporcionadas requieren cargar el entorno Rails, que, en la mayoría de los casos, no es el comportamiento deseado debido a una sobrecarga muy grande y una velocidad muy baja. DatabaseCleanergem también es bastante lento y agrega otra dependencia a su aplicación.

Después de meses de disgusto y disgusto gracias a las razones vide supra, finalmente he encontrado que la siguiente solución es exactamente lo que necesito. Es agradable, simple y rápido. En spec_helper.rb:

config.after :all do
  ActiveRecord::Base.subclasses.each(&:delete_all)
end

La mejor parte de esto es: solo borrará las tablas que haya tocado de manera efectiva (los modelos intactos no se cargarán y, por lo tanto, no aparecerán subclasses, también es la razón por la que esto no funciona antes de las pruebas). Además, se ejecuta después de las pruebas, por lo que los puntos verdes (con suerte) aparecerán de inmediato.

El único inconveniente de esto es que si tiene una base de datos sucia antes de ejecutar las pruebas, no se limpiará. Pero dudo que sea un problema importante, ya que la base de datos de prueba generalmente no se toca desde pruebas externas.

Editar

Dado que esta respuesta ha ganado algo de popularidad, quise editarla para que esté completa: si desea borrar todas las tablas, incluso las que no se han tocado, debería poder hacer algo como los "trucos" a continuación.

Hack 1: precarga de todos los modelos para el subclassesmétodo

Evalúe esto antes de llamar subclasses:

Dir[Rails.root.join("app", "models", "**", "*.rb")].each(&method(:require))

Tenga en cuenta que este método puede llevar algún tiempo.

Hack 2 - truncar las tablas manualmente

ActiveRecord::Base.connection.tables.keep_if{ |x| x != 'schema_migrations' }

obtendrá todos los nombres de las tablas, con los que puede hacer algo como:

case ActiveRecord::Base.configurations[Rails.env]["adapter"]
when /^mysql/, /^postgresql/
  ActiveRecord::Base.connection.execute("TRUNCATE #{table_name}")
when /^sqlite/
  ActiveRecord::Base.connection.execute("DELETE FROM #{table_name}")
  ActiveRecord::Base.connection.execute("DELETE FROM sqlite_sequence where name='#{table_name}'")
end
Danyel
fuente
¡Ordenado! Esto es muy útil.
odigity
3

En una aplicación Rails 4 con muelles, bin/setupnormalmente mi se aumenta para contener

puts "\n== Preparing test database =="
system "RAILS_ENV=test bin/rake db:setup"

Esto es muy similar a la respuesta de leviatán , además de sembrar la base de datos de prueba, como

rake db:setup # Cree la base de datos, cargue el esquema e inicialice con los datos semilla
(use
db:reset para eliminar también la base de datos primero)

Como menciona el comentario, si queremos eliminar la base de datos primero, hagamos rake db:resetprecisamente eso.

También encuentro que esto proporciona más comentarios en comparación con rake db:test:prepare.

Marius Butuc
fuente
0

Empecé descartando mi base de datos de prueba rake db:drop RAILS_ENV=test

al intentar crear una nueva base de datos de prueba, encontré un problema porque mi cuenta de usuario no era la misma que la cuenta que posee las bases de datos, así que creé la base de datos en PostgreSQL.

escriba psqlen el símbolo del sistema y luego ejecute lo siguiente para crear una base de datos de prueba que use una cuenta que no sea la suya. CREATE DATABASE your_database_name OWNER your_db_owner;

luego ejecute sus migraciones en el entorno de prueba. rake db:migrate RAILS_ENV=test

random_user_0891
fuente