1

コードが多すぎるかもしれませんが、RSpec がこのように機能する理由を理解したいと思います。doubleリモート REST API とやり取りする外部オブジェクトを試しています。

コード例:

class App

  class << self
    def foo
      external.func1
    end

    def bar
      external.func2
    end

    def external
      @external ||= ExternalObject.new
    end
  end

end

class ExternalObject
  def func1
    puts 'func1'
  end

  def func2
    puts 'func2'
  end
end

この仕様は機能します:

require 'rspec'
require_relative 'app'

describe App do

  describe '.foo' do
    it 'calls func1' do
      expect_any_instance_of(ExternalObject).to receive(:func1)

      described_class.foo
    end
  end

  describe '.bar' do
    it 'calls func2' do
      expect_any_instance_of(ExternalObject).to receive(:func2)

      described_class.bar
    end
  end

end

しかし、これはうまくいきません:

require 'rspec'
require_relative 'app'

describe App do

  let(:external) { double('ExternalObject', func1: 1, func2: 2) }
  before(:each) do
    allow(ExternalObject).to receive(:new).and_return(external)
  end

  describe '.foo' do
    it 'calls func1' do
      expect(external).to receive(:func1)

      described_class.foo
    end
  end

  describe '.bar' do
    it 'calls func2' do
      expect(external).to receive(:func2)

      described_class.bar
    end
  end

end

2 番目の例を実行すると、RSpec の出力doubleはスタブが含まれていないように見えます。

1) App.bar calls func2
     Failure/Error: described_class.bar
       Double "ExternalObject" received unexpected message :func2 with (no args)

コードを次のように置き換える場合App.external:

@external = ExternalObject.new

すべてがうまく機能します。

そのエラーの理由を検索しましたが、何も見つかりませんでした。

アップデート

また、クラスのメモ化を防ぐために、オブジェクトを複製することができます。たぶんそれは良い考えではありませんが、うまくいきます。

require 'rspec'
require_relative 'app'

describe App do

  let(:external) { double('ExternalObject', func1: 1, func2: 2) }
  before(:each) do
    stub_const('App', App.clone)
    allow(ExternalObject).to receive(:new).and_return(external)
  end

  describe '.foo' do
    it 'calls func1' do
      expect(external).to receive(:func1)

      App.foo
    end
  end

  describe '.bar' do
    it 'calls func2' do
      expect(external).to receive(:func2)

      App.bar
    end
  end

end

更新 2

私は私の質問を具体化します:なぜテストの間doubleにメモ化されたのに、スタブ化され@externalたメソッドがないのですか?

4

1 に答える 1