83

コンテストエントリースペック.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
4

4 に答える 4

129

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

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

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

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

微妙な違いですが重要です

また、

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) }
于 2013-05-17T20:30:31.813 に答える
43

の重要な詳細before :allは、それがDBではないtransactionalということです。つまり、DB に保持されるものはすべてbefore :all、メソッド内で手動で破棄する必要がありますafter :all

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

ただし、DBトランザクションですbefore: each

実証するための簡単なテスト:

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

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

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

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

3.では、これを試してください。

  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

別の疲れた旅行者に役立つことを願っています。

于 2016-06-11T08:23:00.247 に答える
5

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

于 2014-07-22T06:23:06.930 に答える