Les gens semblent avoir expliqué certaines des façons fondamentales dont ils diffèrent, mais les ont laissés de côté before(:all)et n'expliquent pas exactement pourquoi ils devraient être utilisés.
Je pense que les variables d'instance n'ont pas leur place dans la grande majorité des spécifications, en partie pour les raisons mentionnées dans cette réponse , je ne les mentionnerai donc pas ici.
laissez les blocs
Le code à l'intérieur d'un letbloc n'est exécuté que lorsqu'il est référencé, le chargement différé signifie que l'ordre de ces blocs n'est pas pertinent. Cela vous donne une grande quantité d'énergie pour réduire les configurations répétées grâce à vos spécifications.
Un exemple (extrêmement petit et artificiel) de ceci est:
let(:person) { build(:person) }
subject(:result) { Library.calculate_awesome(person, has_moustache) }
context 'with a moustache' do
let(:has_moustache) { true }
its(:awesome?) { should be_true }
end
context 'without a moustache' do
let(:has_moustache) { false }
its(:awesome?) { should be_false }
end
Vous pouvez voir que cela has_moustacheest défini différemment dans chaque cas, mais il n'est pas nécessaire de répéter la subjectdéfinition. Il est important de noter que le dernier letbloc défini dans le contexte actuel sera utilisé. C'est bon pour définir une valeur par défaut à utiliser pour la majorité des spécifications, qui peuvent être écrasées si nécessaire.
Par exemple, vérifier la valeur de retour de calculate_awesomeif passé un personmodèle avec top_hatla valeur true, mais aucune moustache ne serait:
context 'without a moustache but with a top hat' do
let(:has_moustache) { false }
let(:person) { build(:person, top_hat: true) }
its(:awesome?) { should be_true }
end
Une autre chose à noter à propos des blocs let, ils ne doivent pas être utilisés si vous recherchez quelque chose qui a été sauvegardé dans la base de données (c'est-à-dire Library.find_awesome_people(search_criteria)) car ils ne seront pas sauvegardés dans la base de données à moins qu'ils n'aient déjà été référencés. let!ou des beforeblocs sont ce qui devrait être utilisé ici.
Aussi, ne l' utilisez jamaisbefore pour déclencher l'exécution de letblocs, c'est pour cela qu'il let!est fait!
laisser! blocs
let!les blocs sont exécutés dans l'ordre dans lequel ils sont définis (un peu comme un bloc avant). La seule différence fondamentale avec les blocs avant est que vous obtenez une référence explicite à cette variable, plutôt que de devoir revenir aux variables d'instance.
Comme pour les letblocs, si plusieurs let!blocs sont définis avec le même nom, le plus récent est celui qui sera utilisé lors de l'exécution. La principale différence est que les let!blocs seront exécutés plusieurs fois s'ils sont utilisés de cette manière, alors que le letbloc ne s'exécutera que la dernière fois.
avant (: chaque) blocs
before(:each)est le bloc par défaut avant, et peut donc être référencé comme before {}plutôt que de spécifier le plein à before(:each) {}chaque fois.
C'est ma préférence personnelle d'utiliser des beforeblocs dans quelques situations fondamentales. J'utiliserai avant les blocs si:
- J'utilise des moqueries, des stubbing ou des doubles
- Il y a une configuration de taille raisonnable (généralement, c'est un signe que vos caractéristiques d'usine n'ont pas été configurées correctement)
- Il y a un certain nombre de variables que je n'ai pas besoin de référencer directement, mais qui sont requises pour la configuration
- J'écris des tests de contrôleurs fonctionnels dans des rails, et je souhaite exécuter une demande spécifique de test (ie
before { get :index }). Même si vous pouvez l'utiliser subjectdans de nombreux cas, cela semble parfois plus explicite si vous n'avez pas besoin d'une référence.
Si vous vous retrouvez à écrire de gros beforeblocs pour vos spécifications, vérifiez vos usines et assurez-vous de bien comprendre les caractéristiques et leur flexibilité.
avant (: tous) blocs
Celles-ci ne sont exécutées qu'une seule fois, avant les spécifications dans le contexte actuel (et ses enfants). Ceux-ci peuvent être utilisés à bon escient s'ils sont écrits correctement, car dans certaines situations, cela peut réduire l'exécution et les efforts.
Un exemple (qui n'affecterait guère le temps d'exécution) consiste à simuler une variable ENV pour un test, ce que vous ne devriez jamais avoir à faire qu'une seule fois.
J'espère que cela pourra aider :)