web-dev-qa-db-fra.com

rails rspec avant tout vs avant chaque

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
60
Johnny Cash

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) }
96
fontno

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: eachest 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é.

20
wired00

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.

3
Jazib Bashir

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.

0
shiva kumar