Rspec 3.0 如何模拟替换参数但没有返回值的方法?

Posted

技术标签:

【中文标题】Rspec 3.0 如何模拟替换参数但没有返回值的方法?【英文标题】:Rspec 3.0 How to mock a method replacing the parameter but with no return value? 【发布时间】:2014-06-02 12:06:48 【问题描述】:

我已经搜索了很多,但无法弄清楚,尽管它看起来很基本。这是我想要做的简化示例。

创建一个做某事但不返回任何内容的简单方法,例如:

class Test
  def test_method(param)
    puts param
  end
  test_method("hello")
end

但在我的 rspec 测试中,我需要传递不同的参数,例如“再见”而不是“你好”。我知道这与存根和模拟有关,我查看了文档但无法弄清楚:https://relishapp.com/rspec/rspec-mocks/v/3-0/docs/method-stubs

如果我这样做:

@test = Test.new
allow(@test).to_receive(:test_method).with("goodbye")

它告诉我存根一个默认值,但我不知道如何正确地做到这一点。

错误信息:

received :test_method with unexpected arguments
  expected: ("hello")
  got: ("goodbye")
Please stub a default value first if message might be received with other args as well.     

我正在使用 rspec 3.0,并调用类似

@test.stub(:test_method)

不允许。

【问题讨论】:

您的错误信息似乎与您的存根相反。 【参考方案1】:

如何设置默认值,详见

and_call_original can configure a default response that can be overriden for specific args

require 'calculator'

RSpec.describe "and_call_original" do
  it "can be overriden for specific arguments using #with" do
    allow(Calculator).to receive(:add).and_call_original
    allow(Calculator).to receive(:add).with(2, 3).and_return(-5)

    expect(Calculator.add(2, 2)).to eq(4)
    expect(Calculator.add(2, 3)).to eq(-5)
  end
end

我知道的来源可以在https://makandracards.com/makandra/30543-rspec-only-stub-a-method-when-a-particular-argument-is-passed找到

【讨论】:

【参考方案2】:

对于您的示例,由于您不需要测试 test_method 的实际结果,只有在 param 中调用 puts 时,我将通过设置期望并运行方法:

class Test
  def test_method(param)
    puts param
  end
end

describe Test do
  let(:test)  Test.new 

  it 'says hello via expectation' do
    expect(test).to receive(:puts).with('hello')
    test.test_method('hello')
  end

  it 'says goodbye via expectation' do
    expect(test).to receive(:puts).with('goodbye')
    test.test_method('goodbye')
  end
end

您似乎正在尝试在该方法上设置一个test spy,但我认为您将方法存根设置一个级别太高(在@987654326 @ 本身,而不是在 test_method 中调用 puts)。如果您将存根放在对puts 的调用中,您的测试应该通过:

describe Test do
  let(:test)  Test.new 

  it 'says hello using a test spy' do
    allow(test).to receive(:puts).with('hello')
    test.test_method('hello')
    expect(test).to have_received(:puts).with('hello')
  end

  it 'says goodbye using a test spy' do
    allow(test).to receive(:puts).with('goodbye')
    test.test_method('goodbye')
    expect(test).to have_received(:puts).with('goodbye')
  end
end

【讨论】:

谢谢 - 这很有帮助!一方面,我不知道您可以说expect(test).to receive(:puts) - 我以为您只能调用直接方法(此处为test_method),所以很高兴知道。最后,我的实际问题更复杂,我决定只需要更改我的代码来定义 确实 返回值的方法,无论如何这可能是更好的做法。然后很容易使用allow(test).to receive(:test_method).and_return('goodbye')。我确信还有另一种方法可以使用其中的一些,而且了解测试间谍也很好 - 我以前没有遇到过。

以上是关于Rspec 3.0 如何模拟替换参数但没有返回值的方法?的主要内容,如果未能解决你的问题,请参考以下文章

显示每个 rspec 示例的运行时

没有导轨的 rspec 迷你模拟服务器

rspec中的模拟方法链

模拟 Rails.env.development?使用 rspec

Rails 4, RSpec 3.2 - 如何模拟 ActionMailer 的 Deliver_now 方法来引发异常

如何测试具有多个输入调用的循环?