RSpec自定义匹配器保持规格之间的状态

时间:2012-02-27 12:33:15

标签: ruby testing rspec tdd

我在RSpec(2.8.0)自定义匹配器功能中遇到了一些反直觉的行为,我想知道它是一个错误或功能还是我感到困惑。我们来看看代码:

# matcher code
RSpec::Matchers.define :exist do
  chain :with_start_time do |time|
    @start_time = time
  end

  chain :with_end_time do |time|
    @end_time = time
  end

  match do |subject|
    result = true
    result &&= subject.start_time == @start_time if @start_time
    result &&= subject.end_time == @end_time if @end_time
    result
  end

  failure_message_for_should do |subject|
    "Failure!\n".tap do |msg|
      if @start_time != subject.start_time
        msg << "Expected start_time to be #@start_time but was #{subject.start_time}\n"
      end
      if @end_time != subject.end_time
        msg << "Expected end_time to be #@end_time but was #{subject.end_time}\n"
      end
    end
  end
end

#spec code
require 'ostruct'

describe 'RSpec custom matcher keeping state between tests' do
  let(:time) { Time.now }

  it 'passes the first spec' do
    o = OpenStruct.new(start_time: time)
    o.should exist.with_start_time(time)
  end

  it 'fails the second because matcher kept @start_time from the first test' do
    o = OpenStruct.new(end_time: time)
    o.should exist.with_end_time(time)
  end
end

这失败了(证明了问题):

avetia01:~/projects/custom_matcher_bug% rspec test_spec.rb             
.F

Failures:

  1) RSpec custom matcher keeping state between tests fails the second because matcher kept @start_time from the first test
     Failure/Error: o.should exist.with_end_time(time)
       Failure!
       Expected start_time to be 2012-02-27 12:20:25 +0000 but was 
     # ./test_spec.rb:41:in `block (2 levels) in <top (required)>'

Finished in 0.00116 seconds

2 examples, 1 failure


所以意想不到的一点是,相同的匹配器实例似乎在多个规范中使用。在这种特殊情况下导致@start_time使用第一个规范中的值进行初始化,导致第二个规范的错误失败。

1 个答案:

答案 0 :(得分:2)

已报告并已修复,但尚未发布:

https://github.com/rspec/rspec-expectations/issues/104