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)在运行所有示例之前运行该块一次。

before(:each)在文件中的每个规范之前运行该块一次

before(:all)@admission, @project, @creative, @contest_entry在运行所有it块之前设置一次实例变量。

但是,: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) }
于 2013-05-17T20:30:31.813 回答
43

的一个重要细节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

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

于 2016-06-11T08:23:00.247 回答
5

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

于 2014-07-22T06:23:06.930 回答
0

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

于 2018-04-04T07:53:29.440 回答