范围

所有 rspec-mocks 构造都有每个示例的生命周期。消息期望在每个示例后进行验证。替身、方法存根、存根常量等都在每个示例后清理。这确保每个示例可以独立运行,并且可以按任何顺序运行。

在 `before(:example)` 钩子中设置替身、存根和消息期望完全没有问题,因为该钩子在示例范围内执行

  before(:example) do
    allow(MyClass).to receive(:foo)
  end

由于 `before(:context)` 在任何单个示例范围之外运行,因此不支持在其中使用 rspec-mocks 功能。但是,您可以使用 `RSpec::Mocks.with_temporary_scope { }` 在 *任何* 任意上下文中(包括在 `before(:context)` 钩子中)创建临时范围。

无法在 `before(:context)` 钩子中创建替身

给定一个名为“before_context_spec.rb”的文件,其中包含

RSpec.describe "Creating a double in a before(:context) hook" do
  before(:context) do
    @dbl = double(:foo => 13)
  end

  it "fails before it gets to the examples" do
    expect(@dbl.foo).to eq(13)
  end
end

我运行 `rspec before_context_spec.rb`

那么它应该失败,并显示

The use of doubles or partial doubles from rspec-mocks outside of the per-test lifecycle is not supported.

使用 `with_temporary_scope` 在 `before(:context)` 钩子中创建和使用替身

给定一个名为“with_temporary_scope_spec.rb”的文件,其中包含

RSpec.describe "Creating a double in a before(:context) hook" do
  before(:context) do
    RSpec::Mocks.with_temporary_scope do
      dbl = double(:foo => 13)
      @result = dbl.foo
    end
  end

  it "allows a double to be created and used from within a with_temporary_scope block" do
    expect(@result).to eq(13)
  end
end

我运行 `rspec with_temporary_scope_spec.rb`

那么示例应该全部通过。

替身不能在另一个示例中重复使用

给定一个名为“leak_test_double_spec.rb”的文件,其中包含

class Account
  class << self
    attr_accessor :logger
  end

  def initialize
    @balance = 0
  end

  attr_reader :balance

  def credit(amount)
    @balance += amount
    self.class.logger.log("Credited $#{amount}")
  end
end

RSpec.describe Account do
  it "logs each credit" do
    Account.logger = logger = double("Logger")
    expect(logger).to receive(:log).with("Credited $15")
    account = Account.new
    account.credit(15)
  end

  it "keeps track of the balance" do
    account = Account.new
    expect { account.credit(10) }.to change { account.balance }.by(10)
  end
end

我运行 `rspec leak_test_double_spec.rb`

那么它应该失败,并显示以下输出

2 个示例,1 个失败
1) 账户跟踪余额
失败/错误: self.class.logger.log(“Credited $#{amount}”)
#最初是在一个示例中创建的,但泄漏到另一个示例中,现在无法再使用。