레일스 rspec 전과 각 전


79

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

답변:


120

before(:all) 모든 예제가 실행되기 전에 블록을 한 번 실행합니다.

before(:each) 파일의 각 사양 전에 블록을 한 번 실행합니다.

before(:all)@admission, @project, @creative, @contest_entry모든 it블록이 실행 되기 전에 인스턴스 변수를 한 번 설정합니다 .

그러나 블록이 실행될 :before(:each)때마다 이전 블록의 인스턴스 변수를 재설정합니다 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) }

실패한 이유를 알고 있지만 이전과 (각)
세티

38

의 중요한 세부 사항 before :all은 점입니다 하지 DB transactional. 즉, 그 안의 모든 before :all것은 DB에 유지되며 after :all메서드 에서 수동으로 해체해야합니다 .

의미는 테스트 스위트가 완료된 후 변경 사항이 나중에 테스트를 위해 되돌려지지 않는다는 것을 의미합니다. 이로 인해 복잡한 버그와 데이터 교차 오염 문제가 발생할 수 있습니다. 즉, 예외가 발생하면 after :all콜백이 호출되지 않습니다.

그러나 before: each DB 트랜잭션.

시연을위한 빠른 테스트 :

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

다른 지친 여행자에게 도움이되기를 바랍니다.


이 팁은 내 하루를 저장합니다! before to before (: each)
Humberto Corrêa

4

before(:all)이는 블록의 모든 테스트 전에 샘플 사용자가 한 번 생성되도록합니다. 이것은 속도 최적화입니다.


0

한 가지 주목할 점은 기본적으로 before (: each) 사용 전, before (: all)에서도 컨트롤러 인스턴스가 설정되지 않아 요청과 같은 컨트롤러 메서드가 사용되지 않는다는 것입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.