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:

  1. Source de solde de compte a diminué de amount
  2. Destination le solde du compte a augmenté par amount
  3. Enregistrement d'Audit est inséré

Quelle est la meilleure façon de tester la @account.transfer méthode?

Était-ce utile?

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.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top