只模拟一次方法

Jay*_*rka 3 rspec

在替换原始的模拟方法之前,有没有办法模拟一个方法一次且每个期望只模拟一次?

我认为这样的事情会起作用(注意once

class Klass
    def self.meth
        'baz'
    end
end

describe Klass do
    subject{ described_class.meth }
    before{ allow(described_class).to receive(:meth).once.and_return('foo') }
    it{ is_expected.to eq 'foo' }
    context 'throwing in a context just to test' do
        it{ is_expected.to eq 'foo' }
        it{ is_expected.to eq 'foo' }
        it{ is_expected.to eq 'foo' }
        it 'only mocks once' do
            expect(subject).to eq 'foo'
            expect(subject).to eq 'baz' # this is the key
        end # pass
    end
end
Run Code Online (Sandbox Code Playgroud)

不幸的是,我收到此错误:

   (Klass (class)).meth(no args)
       expected: 1 time with any arguments
       received: 2 times
Run Code Online (Sandbox Code Playgroud)

如果我说expect(Klass).to receive(:meth).once而不是更宽容的话,我本来希望会失败allow

我想知道如何才能模拟一次并且每个期望只模拟一次。

Pau*_*nti 6

这或许有点不直观,但是你可以通过做多的呼叫指定不同的返回值Klass.meth

在您的情况下,您可以存根对Klass.methwith的第一次调用'foo',然后存根对Klass.methwith的原始调用的所有其他调用。看起来像这样:

allow(described_class).to receive(:meth).and_return('foo', described_class.meth)

我们需要在您的测试中更改的下一件事是不要subject在最终测试中使用,因为它会记住Klass.meth第一次调用时返回的值(这就是为什么所有其他使用的测试subject仍然会通过),并且因此使it 'only mocks once'测试中的第二个期望失败。相反,我们可以直接在每个规范中调用该方法:

class Klass
  def self.meth
    'baz'
  end
end

describe Klass do
  subject { described_class.meth }

  before do
    allow(described_class).to \
      receive(:meth).and_return('foo', described_class.meth)
  end

  it { is_expected.to eq 'foo' }

  context 'throwing in a context just to test' do
    it { is_expected.to eq 'foo' }
    it { is_expected.to eq 'foo' }
    it { is_expected.to eq 'foo' }

    it 'only mocks once' do
      expect(described_class.meth).to eq 'foo'
      expect(described_class.meth).to eq 'baz'
    end # pass
  end
end
Run Code Online (Sandbox Code Playgroud)