RSpec在钩子之前,之后和周围以什么顺序运行?

时间:2014-05-22 15:40:52

标签: ruby rspec

当我遇到some issue时,我决定检查执行beforeafter个挂钩的顺序。这就是我所做的:

require "spec_helper"

describe "The order:" do

  before(:all) {
    puts "before_all"
  }

  after(:all) {
    puts "after_all"
  }

  before(:each) {
    puts "before_each"
  }

  after(:each) {
    puts "after_each"
  }

  describe "DESC A" do
    before {
      puts "A_before"
    }
    it "A_it_1" do      
      expect(1).to eq(1)
    end
    it "A_it_2" do
      expect(1).to eq(1)
    end
  end

  describe "DESC B" do
    before {
      puts "B_before"
    }
    it "B_it_1" do      
      expect(1).to eq(1)
    end
    it "B_it_2" do
      expect(1).to eq(1)
    end
  end  
end

以及我得到了什么:

The order:

before_all

  DESC A
before_each
A_before
after_each
    A_it_1
before_each
A_before
after_each
    A_it_2
  DESC B
before_each
B_before
after_each
    B_it_1
before_each
B_before
after_each
    B_it_2

after_all

这里发生了什么?为什么after_eachA_it_1之前运行?

更新

添加around(:each)会更有趣:

 around(:each) do |example|
    puts "around_in"
    example.run
    puts "around_out"
  end

和结果:

The order:
before_all
  DESC A
around_in
before_each
A_before
after_each
around_out
    A_it_1
around_in
before_each
A_before
after_each
around_out
    A_it_2
  DESC B
around_in
before_each
B_before
after_each
around_out
    B_it_1
around_in
before_each
B_before
after_each
around_out
    B_it_2
after_all

3 个答案:

答案 0 :(得分:6)

您的输出以及relishapp.com上记录的官方输出是正确的。发生的事情是rspec需要在每个示例之后运行after(:each)es,因为after(:each)中的异常会导致示例失败。在rspec可以在输出中显示示例之前,它需要知道它是绿色还是红色,这意味着在示例的描述出现在输出之前需要运行after(:eaches)。

但是,如果在实际示例中放置了puts语句,您将看到before(:each)es出现在它之前,然后运行示例代码(包括puts),然后是after(:each) es,正如您所期望的那样,最后,示例的描述将输出到屏幕。

和你一样,我也很困惑,直到我意识到rspec打印出的示例标签与它实际做的事情并不一致 - 标签只会打印出来之前(:all)s,before(:each)es和after(:each)之后运行示例。

注意:在打印完示例标签后运行(:all)之后运行,因为它们不会影响测试结果(生成警告,表示在after(:all)挂钩中发生异常,但是这不会使测试变红。)

答案 1 :(得分:4)

RSpec's documentation for before and after hooks指定它们运行的​​顺序。但是,RSpec's documentation for around hooks未指定其运行顺序。

此规范测试执行aroundbeforeafter :all:each以及示例的顺序。当我使用rspec(-core)2.14.8运行它时,它们按照你期望的顺序执行:

describe "order in which rspec around/before/after hooks run" do
  before :all do
    defined?($previous_hook).should be_false # this hook runs first
    $previous_hook = "before :all"
  end

  around :each do |example|
    $previous_hook.should == "before :all"
    $previous_hook = "around :each 1"
    example.run
    $previous_hook.should == "after :each"
    $previous_hook = "around :each 2"
  end

  before :each do
    $previous_hook.should == "around :each 1"
    $previous_hook = "before :each"
  end

  it "should not raise an exception or print anything" do
    $previous_hook.should == "before :each"
    $previous_hook = "example"
  end

  after :each do
    $previous_hook.should == "example"
    $previous_hook = "after :each"
  end

  after :all do
    # rspec ignores assertion failures and any other exceptions raised here, so all we can do is puts.
    # $previous_hook is a global because if it's an instance variable it is "before :all" at this point.
    warn "Previous hook was #{$previous_hook}, NOT around :each 2 as expected" unless $previous_hook == "around :each 2"
  end

end

注意一些可能令人惊讶的事情:

  • self:all:each块中有所不同,因此我需要使用全局变量而不是实例变量。
  • after :all(但不是before :all)吃异常。
  • 查看所有这些地方.should的作品!并不是说你通常想在那里使用它。

答案 2 :(得分:0)

上面已经回答了这个问题,但是添加了一个简单的答案。

要查看钩子以什么顺序运行,还必须在“ it”中添加“ puts”语句

所以

describe "The order:" do

  before(:all) {
    puts "before_all"
  }

  after(:all) {
    puts "after_all"
  }

  before(:each) {
    puts "before_each"
  }

  after(:each) {
    puts "after_each"
  }

  describe "DESC A" do
    before {
      puts "A_before"
    }
    it "A_it_1" do      
      # expect(1).to eq(1)       <<<<---- Change Here
      puts "Inside the test"
    end
  end
end