RSpec unité de test avec plusieurs affirmations
-
21-12-2019 - |
Question
Tout d'abord, je sais que c'est une mauvaise pratique d'avoir plusieurs affirmations contenues dans l'unité de test.
Mais parfois vous avez besoin de tester une transaction atomique.Comme un exemple simplifié, nous allons faire une application bancaire qui a la classe Compte:
class Account
attr_accessor :balance
def transfer(to_account, amount)
self.balance -= amount
to_account.balance += amount
Audit.create(message: "Transferred #{amount} from #{self.number} to #{to_account.number}."
end
end
Dans cette situation, je veux vérifier 3 choses:
- Source de solde de compte a diminué de
amount
- Destination le solde du compte a augmenté par
amount
- Enregistrement d'Audit est inséré
Quelle est la meilleure façon de tester la @account.transfer
méthode?
La solution
Dans cette situation, je veux vérifier 3 choses:
Je dirais que ce que vous voulez vraiment est de décrire le comportement de ces choses, sous certaines conditions, et ainsi s'assurer que le comportement répond à vos spécifications.Cela peut signifier des choses se produire ensemble;ou peut signifier que certaines choses ne se produisent que dans un ensemble de conditions et pas d'autres, ou qu'une exception provoque tout pour être restaurée à son état d'origine.
Il n'y a pas de magie à avoir tous vos affirmations dans un test, sauf à rendre les choses plus vite.Sauf si vous êtes confrontés à une grave dégradation de la performance (comme il arrive souvent en full-stack tests), il est beaucoup mieux d'utiliser une affirmation par test.
RSpec le rend simple pour extraire le test de la phase d'installation de sorte qu'il est répété pour chaque exemple:
class Account
attr_accessor :balance
def transfer(to_account, amount)
self.debit!(amount)
to_account.credit!(amount)
Audit.create!(message: "Transferred #{amount} from #{self.number} to #{to_account.number}."
rescue SomethingBadError
# undo all of our hard work
end
end
describe Account do
context "when a transfer is made to another account" do
let(:other_account} { other_account }
context "and the subject account has sufficient funds" do
subject { account_with_beaucoup_bucks }
it "debits the subject account"
it "credits the other account"
it "creates an Audit entry"
end
context "and the subject account is overdrawn" do
subject { overdrawn_account }
it "does not debit the subject account"
it "does not credit the other account"
it "creates an Audit entry" # to show the attempted transfer failed
end
end
end
Si tous les trois essais dans les "heureux" chemin de passé, puis ils ont tous "passé ensemble", depuis le premier état du système a été la même dans chaque cas.
Mais vous devez également vous assurer que les choses ne pas se produire lorsque quelque chose va mal, et que le système retourne à son état d'origine.Le fait d'avoir plusieurs assertions, il est facile de voir que cela fonctionne comme prévu, et lorsque les tests échouent, exactement comment ils ont échoué.
Autres conseils
Plusieurs affirmations par test n'est pas toujours une mauvaise pratique.Si les multiples affirme vérifiez le même comportement, il n'y a pas de problème avec elle.Le problème lorsque vous essayez de vérifier plus d'un comportement dans le même test.Bien sûr il y a des risques avec de multiples affirme par test.L'un d'eux est que vous risquez de laisser les valeurs à partir d'un précédent jeu de test qui annule un précédent essai d'une manière bizarre.Aussi, quand une assertion est fausse, toute l'autre gauche ne sera pas exécuté, ce qui peut causer de la difficulté à comprendre ce qui est goin sur.Mais soyez raisonnable, vous pouvez avoir plusieurs affirme affirmant le même comportement, de préférence court et sans installation supplémentaire.
Dans le cas simple que vous avez apporté, je voudrais utiliser de multiples affirme, parce que c'est si simple.Mais bien sûr, il peut devenir beaucoup plus compliqué, à l'instar de solde négatif, les différents types de comptes et d'autres choses.Ensuite, il serait préférable d'utiliser différents tests avec un (de préférence) faire valoir.Je voudrais organiser comme ceci:
- 1 pour tester le comportement du Compte courant (plus simple des cas);
- 1 pour chaque chemin différent de la méthode peut avoir (des exceptions, négatif etc.);
1 pour test de Vérification dans chaque de ces possibilités;
1 pour tester le comportement de l'actuel to_account (plus simple des cas);
- 1 pour chaque chemin différent de la méthode peut avoir.(des exceptions, négatif solde etc.) ;
- 1 pour test de Vérification dans chaque de ces possibilités;
Depuis la Vérification, le test est assez simple et ne nécessite pas d'installation supplémentaire, vous pouvez également tester avec un Compte et to_account.