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
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) }
_
_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
別の疲れた旅行者を助けることを願っています。
before(:all)
。ブロック内のすべてのテストの前に、サンプルユーザーが1回作成されるようにします。これは速度の最適化です。
注意すべきことの1つは、before(:each)を使用する前のデフォルトです。また、before(:all)でもコントローラーインスタンスが設定されていないため、requestなどのコントローラーメソッドは使用されません。