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


78

Competition_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

Answers:


120

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

你知道为什么为什么失败但是之前(:each)
sethi

38

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

希望可以帮助另一个疲倦的旅行者。


这些技巧可以挽救我的一天!只需在before之前写(:每个)
HumbertoCorrêa18年


0

需要注意的一件事是,默认情况下在使用before(:each)之前,同样在before(:all)中也未设置控制器实例,因此不使用诸如request之类的控制器方法。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.