1

まず第一に、単体テストで複数のアサーションを使用するのは悪い習慣であることを知っています。

ただし、アトミック トランザクションをテストする必要がある場合もあります。簡単な例として、Account クラスを持つ銀行アプリケーションを見てみましょう。

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

この状況では、3 つのことをまとめて確認したいと思います。

  1. 元の口座残高が減少amount
  2. 送金先口座の残高が増加amount
  3. 監査記録が挿入されます

メソッドをテストする最良の方法は何@account.transferですか?

4

2 に答える 2

2

この状況では、3 つのことをまとめて確認したいと思います。

あなたが本当に望んでいるのは、特定の条件下でのこれらの動作を記述し、その動作が仕様を満たしていることを確認することだと私は主張します。それは、物事が一緒に起こることを意味するかもしれません。または、ある条件セットでのみ発生し、他の条件では発生しないこと、または例外によりすべてが元の状態にロールバックされることを意味する場合があります。

すべてのアサーションを 1 つのテストで処理する魔法はありませんが、高速化は別です。(フルスタック テストでよくあるように) 深刻なパフォーマンスの低下に直面していない限り、テストごとに 1 つのアサーションを使用する方がはるかに優れています。

RSpec では、テスト セットアップ フェーズを簡単に抽出して、例ごとに繰り返すことができます。

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

「ハッピー パス」の 3 つのテストすべてに合格した場合、最初のシステム状態はいずれの場合も同じだったため、それらはすべて「一緒に発生」しました。

ただし、何か問題が発生したときに、システムが元の状態に戻らないようにする必要もあります。複数のアサーションを使用すると、これが期待どおりに機能すること、およびテストが失敗したときに正確にどのように失敗したかを簡単に確認できます。

于 2014-07-31T22:48:18.223 に答える
1

テストごとに複数のアサーションを行うことは、必ずしも悪い習慣ではありません。複数のアサートが同じ動作を検証する場合、問題はありません。同じテストで複数の動作を検証しようとすると、問題が発生します。もちろん、テストごとに複数のアサートを行うことにはいくつかのリスクがあります。そのうちの 1 つは、前のテスト セットの値を誤って残してしまい、前のテストを奇妙な方法で無効にする可能性があることです。また、1 つの assert が false の場合、残りの残りはすべて実行されず、何が起こっているのかを理解するのが困難になる可能性があります。ただし、合理的に考えて、同じ動作をアサートする複数のアサートを使用できます。できれば短いもので、追加のセットアップは必要ありません。

あなたが持ってきた単純なケースでは、非常に単純なので、複数のアサートを使用します。しかしもちろん、マイナス残高やさまざまな種類のアカウントなど、もっと複雑になる可能性があります。その場合は、1 つの (できれば) アサートで異なるテストを使用することをお勧めします。私はそれを次のように整理します:

  • 1 現在のアカウントの動作をテストします (最も単純なケース)。
  • メソッドが持つことができるすべての異なるパス (例外、負の残高など) に対して 1。
  • 1 これらの可能性のすべてで Audit をテストします。

  • 1 は現在の to_account の動作をテストします (最も単純なケース)。

  • メソッドが持つことができるすべての異なるパスに1。(例外、マイナス残高など) ;
  • 1 これらの可能性のすべてで Audit をテストします。

Audit テストは非常にシンプルで追加の設定が不要なため、Account および to_account と一緒にテストすることもできます。

于 2014-07-31T04:14:00.883 に答える