http://betterspecs.org/#subject a quelques infos à propos de subject
et let
. Cependant, je suis toujours dans le flou sur la différence entre eux. En outre, le post qu'est-Ce que l'argument contre l'utilisation de la avant de, que et soumis à des tests RSpec? dit qu'il est préférable de ne pas utiliser subject
ou let
. Où irai-je? Je suis tellement confus.
Réponses
Trop de publicités?Résumé: RSpec de l'objet est une variable spéciale qui se réfère à l'objet testé. Les attentes peuvent être définies de manière implicite, qui prend en charge une ligne exemples. Il est clair pour le lecteur, dans certains idiomatiques cas, mais il est par ailleurs difficile à comprendre, et devrait être évitée. De RSpec let
variables sont juste paresseusement instancié (memoized) variables. Ils ne sont pas aussi difficile à suivre, car le sujet, mais elle peut encore conduire à des enchevêtrements de tests et doit donc être utilisé avec discrétion.
Le sujet
Comment ça marche
Le sujet est l'objet testé. RSpec a une idée explicite de l'objet. Il peut ou peut ne pas être défini. Si elle l'est, RSpec peut appeler des méthodes sur elle sans la nommer explicitement.
Par défaut, si le premier argument d'une ultrapériphériques exemple de groupe (describe
ou context
block) est une classe, RSpec crée une instance de cette classe et l'attribue à l'objet. Par exemple, les passes suivants:
class A
end
describe A do
it "is instantiated by RSpec" do
expect(subject).to be_an(A)
end
end
Vous pouvez définir le sujet vous-même avec subject
:
describe "anonymous subject" do
subject { A.new }
it "has been instantiated" do
expect(subject).to be_an(A)
end
end
Vous pouvez donner à l'objet un nom lorsque vous définir:
describe "named subject" do
subject(:a) { A.new }
it "has been instantiated" do
expect(a).to be_an(A)
end
end
Même si vous avez le nom de l'objet, vous pouvez toujours vous y référer de façon anonyme:
describe "named subject" do
subject(:a) { A.new }
it "has been instantiated" do
expect(subject).to be_an(A)
end
end
Vous pouvez définir plus d'un nommé sujet. Plus récemment défini nommé le sujet est l'anonyme subject
.
Cependant, le sujet est défini,
Il est instancié paresseusement. C'est, de l'implicite à l'instanciation de la description de la classe ou de l'exécution d'un bloc transmis
subject
n'arrive pas jusqu'subject
ou le nom sujet est fait référence dans un exemple. Si vous voulez que votre explicit sujet pour être instancié avec impatience (avant un exemple dans son groupe de pistes), diresubject!
au lieu desubject
.-
Les attentes peuvent être définies implicitement (sans écrire
subject
ou le nom d'un nommé sous réserve):describe A do it { is_expected.to be_an(A) } end
Le sujet existe à l'appui de cette syntaxe de la ligne.
Quand l'utiliser
Implicite subject
(déduite à partir de l'exemple du groupe) est difficile à comprendre, parce que
- Il est instancié en coulisses.
- Si elle est utilisée implicitement (en appelant
is_expected
sans explicite récepteur) ou explicitement (commesubject
), il donne au lecteur aucune information sur le rôle ou de la nature de l'objet sur lequel on s'attend à ce que l'on appelle. - Le one-liner exemple de syntaxe n'est pas un exemple de description (l'argument de la chaîne d'
it
dans l'exemple normal de la syntaxe), de sorte que les seules informations que le lecteur a sur le but de l'exemple est l'attente elle-même.
Par conséquent, c'est seulement utile pour l'utilisation implicite de l'objet lorsque le contexte est susceptible d'être bien compris par tous les lecteurs et il n'y a vraiment pas besoin d'un exemple de description. Le procès canonique est de tester ActiveRecord des validations avec shoulda de rapprochement:
describe Article do
it { is_expected.to validate_presence_of(:title) }
end
Un explicit anonyme subject
(défini avec subject
sans nom) est un peu mieux, parce que le lecteur peut voir comment il est instancié, mais
- il peut tout de même mettre l'instanciation de l'objet loin de l'endroit où il est utilisé (par exemple, au-dessus d'un exemple de groupe avec de nombreux exemples d'utilisation), ce qui est toujours difficile à suivre, et
- il a d'autres problèmes que l'implicite n'est.
Un nom de sujet fournit une intention de révéler son nom, mais la seule raison d'utiliser un nom de sujet au lieu de let
variable est si vous voulez utiliser l'anonyme sous réserve de temps en temps, et nous avons expliqué pourquoi l'anonyme sujet est difficile à comprendre.
Ainsi, les usages légitimes de l'explicite anonyme subject
ou un nom de sujet sont très rares.
let
variables
Comment ils fonctionnent
let
variables sont comme nommé sujets à deux différences près:
- elles sont définies avec
let
/let!
au lieu desubject
/subject!
- ils ne sont pas ensemble l'anonyme
subject
ou de permettre à des attentes d'être appelée implicitement.
Quand les utiliser
C'est tout à fait légitime d'utiliser let
afin de réduire les doubles emplois entre les exemples. Cependant, faites-le uniquement quand il n'est pas le sacrifice de test de la clarté. Le moment le plus sûr à utiliser let
, c'est quand l' let
de la variable objectif est tout à fait clair à partir de son nom (de sorte que le lecteur n'a pas à trouver la définition, qui pourrait être de plusieurs lignes, pour comprendre chaque exemple) et il est utilisé de la même manière dans chaque exemple. Si l'une de ces choses n'est pas vrai, envisager de définir l'objet dans un simple vieux variable locale ou l'appel d'une méthode de fabrique de la droite dans l'exemple.
let!
est risqué, car il n'est pas paresseux. Si quelqu'un ajoute un exemple à l'exemple de groupe qui contient l' let!
, mais l'exemple n'a pas besoin de l' let!
variable,
- cet exemple va être difficile à comprendre, parce que le lecteur va voir l'
let!
variable et se demander si et comment il affecte l'exemple - l'exemple sera plus lente qu'elle ne doit l'être, en raison du temps pris pour créer l'
let!
variablle
Donc, utiliser l' let!
, si ce n'est dans les petites, simple exemple des groupes où il est moins probable que les futures exemple écrivains vont tomber dans ce piège.
La seule attente par exemple fétiche
Il y a une commune de la surexploitation des sujets ou let
variables qui vaut la peine d'en discuter séparément. Certaines personnes aiment à l'utiliser comme ceci:
describe 'Calculator' do
describe '#calculate' do
subject { Calculator.calculate }
it { is_expected.to be >= 0 }
it { is_expected.to be <= 9 }
end
end
(Ceci est un exemple simple d'une méthode qui retourne un nombre pour lequel nous avons besoin de deux attentes, mais ce style peut avoir beaucoup plus d'exemples/attentes si la méthode renvoie une plus compliqué valeur qui a besoin de beaucoup d'attentes et/ou a de nombreux effets secondaires qui ont besoin attentes.)
Les gens font cela parce qu'ils ont entendu dire que l'on devrait avoir une seule attente par exemple (ce qui est mélangé avec de la validité de la règle que l'on ne devrait tester une méthode d'appel par exemple) ou parce qu'ils sont dans l'amour avec RSpec trickiness. Ne pas le faire, que ce soit avec un anonyme ou le nom de l'objet ou un let
variable! Ce style a plusieurs problèmes:
- L'anonyme sujet n'est pas l'objet de la exemples de la méthode est l'objet. L'écriture du test de cette façon vis de la langue, ce qui rend plus difficile à penser.
- Comme toujours, avec des exemples de ligne, il n'y a pas de place à expliquer le sens des attentes.
- Le sujet doit être construit pour chaque exemple, qui est lent.
Au lieu de cela, écrire un seul exemple:
describe 'Calculator' do
describe '#calculate' do
it "returns a single-digit number" do
result = Calculator.calculate
expect(result).to be >= 0
expect(result).to be <= 9
end
end
end
Subject
et let
sont simplement des outils pour vous aider à nettoyer et accélérer votre tests. Les gens dans la rspec de la communauté ne les utiliser donc je ne vous inquiétez pas de savoir si c'est ok pour les utiliser ou pas. Ils peuvent être utilisés de la même manière, mais de servir des objectifs légèrement différents
Subject
vous permet de déclarer un sujet de test, puis les réutiliser pour n'importe quel nombre de la suite de cas de test par la suite. Cela réduit la répétition de code (Séchage de votre code)
Let
est une alternative à l' before: each
blocs, qui assigne à des données de test pour les variables d'instance. Let
vous donne quelques avantages. Tout d'abord, il met en cache la valeur sans l'affecter à une variable d'instance. Deuxièmement, il est paresseusement évalués, ce qui signifie qu'elle ne soit pas évalué jusqu'à une spécification de la demande. Ainsi, let
vous aide à accélérer votre tests. Je pense aussi qu' let
est plus facile à lire