Après un important dépannage, j'ai compris que je devais exécuter rake spec
une fois (je peux abandonner avec control-c) avant de pouvoir exécuter directement rspec (par exemple, sur un sous-ensemble de nos spécifications). Nous courons Rails 3.0.7 et RSpec 2.5.0.
Clairement, rake exécute d'importantes tâches/codes d'installation de la base de données (nous avons du code personnalisé au niveau racine Rails Rakefile et éventuellement d'autres emplacements).
Comment puis-je exécuter les tâches/le code de configuration de la base de données rake test sans exécuter rake spec
?
En plus de pouvoir exécuter rspec sur un sous-ensemble de fichiers, j'utilise specjour pour étendre nos spécifications sur plusieurs cœurs (je n'ai pas encore réussi à les diffuser sur le réseau local), mais je vois le même comportement que pour exécuter directement rspec: je dois exécuter rake spec
sur chaque base de données de test (en supposant deux cœurs) avant que specjour ne fonctionne:
rake spec TEST_ENV_NUMBER=1
control-c (after tests start)
rake spec TEST_ENV_NUMBER=2
control-c (after tests start)
specjour
Remarque: mon config/database.yml a cette entrée pour test (comme il est courant pour les gems de test en parallèle):
test:
adapter: postgresql
encoding: unicode
database: test<%=ENV['TEST_ENV_NUMBER']%>
username: user
password:
parallel_tests semble configurer correctement ses bases de données, mais bon nombre de nos spécifications échouent.
Je devrais aussi mentionner que courir specjour prepare
permet à Postgres de consigner les erreurs qui empêchent de trouver les bases de données, mais il les crée (sans tables). Lors d'une exécution ultérieure, aucune erreur n'est consignée, mais aucune table n'est créée. Il est possible que tout mon problème soit simplement un bogue dans prepare
, alors je l'ai signalé sur github.
Je pense que je peux exécuter du code arbitraire sur chaque base de données de specjour test en définissant Specjour::Configuration.prepare
dans .specjour/hooks.rb, donc s’il ya des tâches de rake ou un autre code que je dois exécuter, cela peut fonctionner ici.
J'ai eu un problème similaire lors de la configuration du système CI au travail, j'ai donc progressivement mis au point un système pour gérer cela. Ce n'est peut-être pas la meilleure solution, mais cela fonctionne pour moi dans ma situation et je suis toujours à la recherche de meilleures façons de faire les choses.
J'ai une base de données de tests pour laquelle j'avais besoin d'une configuration, mais j'avais également besoin de données initiales chargées pour que nos tests fonctionnent.
L'essentiel du dépannage des tâches de rake consiste à exécuter rake avec l'option --trace pour voir ce qui se passe sous le capot. Lorsque j'ai fait cela, j'ai constaté que l'exécution de rake spec faisait un certain nombre de choses que je pouvais répliquer (ou modifier à ma guise) dans une tâche de rake personnalisée.
Voici un exemple de ce que nous faisons.
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
Ceci est seulement un exemple, et spécifique à notre situation, vous aurez donc besoin de comprendre ce qui doit être fait pour obtenir votre configuration de base de données de test, mais il est assez facile de le déterminer en utilisant l’option --trace de rake.
De plus, si vous trouvez que la configuration du test prend trop de temps (comme dans notre cas), vous pouvez aussi vider la base de données au format .sql et laisser la base de données de test la diriger directement dans mysql pour qu'elle soit chargée. Nous économisons ainsi plusieurs minutes de la configuration de la base de données test. Je ne montre pas cela ici parce que cela complique considérablement les choses - il doit être généré correctement sans devenir obsolète, etc.
HTH
Je recommanderais de supprimer votre base de données de test, puis de la recréer et de migrer:
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
Après ces étapes, vous pouvez exécuter vos spécifications:
bundle exec rspec spec
gerry a noté que:
Une solution plus simple consiste simplement à lancer
rake db:test:prepare
Toutefois, si vous utilisez PostgreSQL, cela ne fonctionnera pas car l’environnement Rails est chargé, ce qui ouvre une connexion à une base de données. Ceci entraîne l’échec de l’appel prepare
car la base de données ne peut pas être laissé tomber.
Les solutions fournies nécessitent toutes de charger l’environnement Rails, qui, dans la plupart des cas, n’est pas le comportement souhaité, en raison de la surcharge très importante et de la très faible vitesse. DatabaseCleaner
gem est également plutôt lent, et cela ajoute une autre dépendance à votre application.
Après des mois de chagrin et de dépit, grâce aux raisons énoncées plus haut, j’ai finalement trouvé la solution suivante parfaitement adaptée à mes besoins. C'est gentil, simple et rapide. Dans spec_helper.rb
:
config.after :all do
ActiveRecord::Base.subclasses.each(&:delete_all)
end
La meilleure partie de ceci est: Cela effacera uniquement les tables que vous avez effectivement touché (Les modèles non modifiés ne seront pas chargés et n'apparaîtront donc pas dans subclasses
, ce qui explique également pourquoi pas travailler avant tests). En outre, il est exécuté après les tests, de sorte que les points verts (espérons-le) apparaîtront immédiatement.
Le seul inconvénient est que si vous avez une base de données sale avant d'exécuter des tests, elle ne sera pas nettoyée. Mais je doute qu'il s'agisse d'un problème majeur, car la base de données de tests n'est généralement pas touchée par des tests externes.
Considérant que cette réponse a acquis une certaine popularité, je voulais l’éditer de manière exhaustive: si vous voulez effacer les tables toutes, même celles qui ne sont pas touchées, vous devriez pouvoir faire quelque chose comme les "bidouilles". au dessous de.
subclasses
Evaluez ceci avant d'appeler subclasses
:
Dir[Rails.root.join("app", "models", "**", "*.rb")].each(&method(:require))
Notez que cette méthode peut prendre un certain temps!
ActiveRecord::Base.connection.tables.keep_if{ |x| x != 'schema_migrations' }
vous obtiendrez tous les noms de table, avec ceux que vous pouvez faire quelque chose comme:
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
Il semble que dans Rails 4.1+, la meilleure solution consiste simplement à ajouter ActiveRecord::Migration.maintain_test_schema!
dans votre Rails_helper après require 'rspec/Rails'
.
c'est-à-dire que vous n'avez plus à vous soucier de la préparation de la base de données.
https://relishapp.com/rspec/rspec-Rails/docs/upgrade#pending-migration-checks
Dans un print-ified Rails 4 app, mon bin/setup
est généralement augmenté pour contenir
puts "\n== Preparing test database =="
system "Rails_ENV=test bin/rake db:setup"
Ceci est très similaire à réponse de leviathan , plus l'ensemencement du test DB, comme
rake db:setup
# Créer la base de données, charger le schéma et initialiser avec les données de départ
(utilisezdb:reset
pour supprimer également la base de données en premier)
Comme le commentaire le mentionne, si nous voulons supprimer le DB en premier, rake db:reset
fait juste cela.
Je trouve également que cela fournit plus de commentaires par rapport à rake db:test:prepare
.