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 let
bloc 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_moustache
est défini différemment dans chaque cas, mais il n'est pas nécessaire de répéter la subject
définition. Il est important de noter que le dernier let
bloc 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_awesome
if passé un person
modèle avec top_hat
la 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 before
blocs sont ce qui devrait être utilisé ici.
Aussi, ne l' utilisez jamaisbefore
pour déclencher l'exécution de let
blocs, 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 let
blocs, 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 let
bloc 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 before
blocs 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 subject
dans 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 before
blocs 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 :)