在每个之前的所有vs之前的轨道rspec

时间:2013-05-17 20:06:41

标签: ruby-on-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

当我运行这些测试时,一切都很好,但如果我在之前(:all)之前更改(之前)(每次),那么每次测试都会失败。我不知道为什么会发生这种情况?

这是错误

 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 个答案:

答案 0 :(得分:101)

在运行所有示例之前,

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) }

答案 1 :(得分:23)

before :all的一个重要细节是它 DB transactional。即,before :all中的任何内容都会持续存在于数据库中,您必须手动拆除after :all方法。

含义意味着在测试套件完成后,更改不会为以后的测试做好准备。这可能导致复杂的错误和数据交叉污染的问题。即,如果抛出异常,则不会调用after :all回调。

但是,before: each 数据库事务。

快速测试以证明:

1。截断相应的数据库表,然后尝试这个,

  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

希望能帮助另一个疲惫的旅行者。

答案 2 :(得分:4)

before(:all),确保在块中的所有测试之前创建一次示例用户。这是对速度的优化。

答案 3 :(得分:0)

有一点需要注意的是默认情况下在使用之前(:each),也在before(:all)之前未设置控制器实例,因此控制器方法就像请求未使用一样。