web-dev-qa-db-ja.com

railsすべての前と各前のrspec

contest_entry_spec.rb

    require 'spec_helper'

    describe ContestEntry do

      before(:all) do
        @admission=Factory(:project_admission)
        @project=Factory(:project_started, :project_type => @admission.project_type)
        @creative=Factory(:approved_creative, :creative_category => @admission.creative_category)
        @contest_entry=Factory(:contest_entry, :design_file_name => 'bla bla bla', :owner => @creative, :project => @project)
      end

      context 'non-specific tests' do
        subject { @contest_entry }
        it { should belong_to(:owner).class_name('User') }
        it { should belong_to(:project) }
        it { should have_many(:entry_comments) }

        it { should validate_presence_of(:owner) }
        it { should validate_presence_of(:project) }
        it { should validate_presence_of(:entry_no) }
        it { should validate_presence_of(:title) }

      end
end

これらのテストを実行するとすべてが順調ですが、before(:all)をbefore(:each)に変更すると、すべてのテストが失敗します。なぜそれが起こるのかわかりませんか?

これはエラーです

 Failure/Error: @contest_entry=Factory(:contest_entry, :design_file_name => 'bla bla bla', :owner => @creative, :project => @project)
     ActiveRecord::RecordInvalid:
       Validation Failed: User is not allowed for this type of project
70
Johnny Cash

before(:all)は、すべての例が実行される前にブロックを1回実行します。

before(:each)は、ファイル内の各仕様の前に1回ブロックを実行します

before(:all)は、すべてのitブロックが実行される前に、インスタンス変数_@admission, @project, @creative, @contest_entry_を1回設定します。

ただし、:before(:each)は、itブロックが実行されるたびに、beforeブロックのインスタンス変数をリセットします。

その微妙な違いは重要です

再び、

_before(:all)
#before block is run
it { should belong_to(:owner).class_name('User') }
it { should belong_to(:project) }
it { should have_many(:entry_comments) }

it { should validate_presence_of(:owner) }
it { should validate_presence_of(:project) }
it { should validate_presence_of(:entry_no) }
it { should validate_presence_of(:title) }

before(:each)
# before block
it { should belong_to(:owner).class_name('User') }
# before block
it { should belong_to(:project) }
# before block
it { should have_many(:entry_comments) }
# before block

# before block
it { should validate_presence_of(:owner) }
# before block
it { should validate_presence_of(:project) }
# before block
it { should validate_presence_of(:entry_no) }
# before block
it { should validate_presence_of(:title) }
_
106
fontno

_before :all_の重要な詳細は、それがnot DB transactionalであることです。つまり、_before :all_内のすべてはDBに保持されるため、手動で_after :all_メソッドを破棄する必要があります。

含意とは、テストスイートが完了した後、変更が後のテストの準備が整っていないことを意味します。これにより、複雑なバグやデータの相互汚染の問題が発生する可能性があります。つまり、例外がスローされた場合、_after :all_コールバックは呼び出されません。

ただし、_before: each_ is DBトランザクション。

デモンストレーションの簡単なテスト:

1。適切なDBテーブルを切り捨ててから、これを試してください。

_  before :all do
    @user = Fabricate(:user, name: 'Yolo')
  end
_

2。その後データベースを観察モデルは永続化されたままです

_after :all_が必要です。ただし、テストで例外が発生した場合、フローが中断されたため、このコールバックは発生しません。データベースは不明な状態のままになるため、CI/CD環境および自動テストでは特に問題が発生する可能性があります。

今、これを試してください、

_  before :each do
    @user = Fabricate(:user, name: 'Yolo')
  end
_

4。データベースにはデータがありませんテストスイートの完了後。はるかに優れており、テストの実行後に一貫した状態を維持します。

要するに、_before :each_はおそらくあなたが望むものです。テストの実行はわずかに遅くなりますが、それだけの価値があります。

詳細はこちら: https://relishapp.com/rspec/rspec-Rails/docs/transactions 参照:Data created in before(:all) are not rolled back

別の疲れた旅行者を助けることを願っています。

28
wired00

before(:all)。ブロック内のすべてのテストの前に、サンプルユーザーが1回作成されるようにします。これは速度の最適化です。

4
Jazib Bashir

注意すべきことの1つは、before(:each)を使用する前のデフォルトです。また、before(:all)でもコントローラーインスタンスが設定されていないため、requestなどのコントローラーメソッドは使用されません。

0
shiva kumar