contest_entry_spec.rb
require 'spec_helper'
describe ContestEntry do
before(:all) do
@admission=Factory(:project_admission)
@project=Factory(:project_started, :project_type => @admission.project_type)
@creative=Factory(:approved_creative, :creative_category => @admission.creative_category)
@contest_entry=Factory(:contest_entry, :design_file_name => 'bla bla bla', :owner => @creative, :project => @project)
end
context 'non-specific tests' do
subject { @contest_entry }
it { should belong_to(:owner).class_name('User') }
it { should belong_to(:project) }
it { should have_many(:entry_comments) }
it { should validate_presence_of(:owner) }
it { should validate_presence_of(:project) }
it { should validate_presence_of(:entry_no) }
it { should validate_presence_of(:title) }
end
end
Lorsque je lance ces tests, tout est ok, mais si je change avant (: tous) en avant (: chaque), chaque test échouera. Je ne sais pas pourquoi cela se produit?
C'est l'erreur
Failure/Error: @contest_entry=Factory(:contest_entry, :design_file_name => 'bla bla bla', :owner => @creative, :project => @project)
ActiveRecord::RecordInvalid:
Validation Failed: User is not allowed for this type of project
before(:all)
exécute le bloc une fois avant que tous les exemples ne soient exécutés.
before(:each)
exécute le bloc une fois avant chacune de vos spécifications dans le fichier
before(:all)
définit les variables d'instance @admission, @project, @creative, @contest_entry
une fois avant que tous les blocs it
soient exécutés.
Cependant, :before(:each)
réinitialise les variables d'instance du bloc before chaque fois qu'un bloc it
est exécuté.
C'est une distinction subtile mais importante
encore,
before(:all)
#before block is run
it { should belong_to(:owner).class_name('User') }
it { should belong_to(:project) }
it { should have_many(:entry_comments) }
it { should validate_presence_of(:owner) }
it { should validate_presence_of(:project) }
it { should validate_presence_of(:entry_no) }
it { should validate_presence_of(:title) }
before(:each)
# before block
it { should belong_to(:owner).class_name('User') }
# before block
it { should belong_to(:project) }
# before block
it { should have_many(:entry_comments) }
# before block
# before block
it { should validate_presence_of(:owner) }
# before block
it { should validate_presence_of(:project) }
# before block
it { should validate_presence_of(:entry_no) }
# before block
it { should validate_presence_of(:title) }
Un détail important de before :all
est qu'il s'agit de non DB transactional
. Autrement dit, tout ce qui se trouve dans le before :all
persiste dans la base de données et vous devez supprimer manuellement la méthode after :all
.
Les implications signifient qu'après la fin des suites de tests, les modifications ne sont pas annulées et prêtes pour des tests ultérieurs. Cela peut entraîner des bogues complexes et des problèmes de contamination croisée des données. Autrement dit, si une exception est levée, le rappel after :all
n'est pas appelé.
Cependant, before: each
est une transaction de base de données.
Un test rapide pour démontrer:
1. tronquez votre table de base de données appropriée puis essayez ceci,
before :all do
@user = Fabricate(:user, name: 'Yolo')
end
2. Observe ensuite la base de données le modèle reste conservé!
after :all
est requis. Cependant, si une exception se produit dans votre test, ce rappel ne se produira pas car le flux a été interrompu. La base de données restera dans un état inconnu, ce qui peut être particulièrement problématique avec les environnements CI/CD et les tests automatisés.
3. maintenant, essayez ceci,
before :each do
@user = Fabricate(:user, name: 'Yolo')
end
4. Maintenant la base de données reste vide de données une fois la suite de tests terminée. Beaucoup mieux et nous laisse avec un état cohérent après l'exécution des tests.
En bref, before :each
, est probablement ce que vous voulez. Vos tests se dérouleront un peu plus lentement, mais cela en vaut la peine.
Détails ici: https://relishapp.com/rspec/rspec-Rails/docs/transactions Voir: Data created in before(:all) are not rolled back
Espérons que cela aide un autre voyageur fatigué.
before(:all)
, qui garantit que les exemples d'utilisateurs sont créés une fois, avant tous les tests du bloc. Ceci est une optimisation pour la vitesse.
Une chose à noter est par défaut avant utilisation avant (: each), également avant ((tout)), l’instance de contrôleur n’est pas définie de sorte que les méthodes de contrôleur telles que request ne sont pas utilisées.