RSpec 的钩子之前、之后和周围的顺序是什么?



由于我面临一些问题,我决定检查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_each为什么在A_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

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

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

像你一样,我也很困惑,直到我意识到rspec打印出示例的标签与它实际做的事情不一致——标签只有在(:all)s之前,(:each)es之前和(:each)es之后为示例运行一次。

注意:after(:all)会在打印出示例标签后运行,因为它们不会影响测试的结果(在after(:all)钩子中会生成一个异常警告,但这不会使测试变为红色)。

RSpec的beforeafter钩子的文档指定了它们运行的顺序。然而,RSpec的around钩子的文档并没有指定它们运行的顺序。

该规范测试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工作的所有地方!你通常不会想在那里使用它。

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

要查看钩子运行的顺序,您必须在"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

最新更新