【问题标题】:rails rspec before all vs before eachrails rspec before all vs before each
【发布时间】:2013-05-13 02:16:13
【问题描述】:

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

【问题讨论】:

    标签: ruby-on-rails rspec


    【解决方案1】:

    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 到 before(:each)
    【解决方案2】:

    需要注意的一点是默认使用 before(:each) 之前,同样在 before(:all) 中,控制器实例未设置,因此未使用请求等控制器方法。

    【讨论】:

      【解决方案3】:

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

      【讨论】:

        【解决方案4】:

        before(:all) 在运行所有示例之前运行该块一次。

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

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

        但是,: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(:each) 失败了
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-05-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-05-19
        相关资源
        最近更新 更多