【问题标题】:RSpec argument matcher for method that includes an optional parameter包含可选参数的方法的 RSpec 参数匹配器
【发布时间】:2014-07-19 11:14:19
【问题描述】:

我有一个具有以下签名的方法

def my_method(first, second = {})

因此它可以通过两种方式调用...

my_method 'first'
my_method 'first', { second: 'value' }

我只对在我的测试中测试第一个参数的值感兴趣,因此我试图提出一个 RSpec 匹配器语句来完成这项工作。我的衣橱是

expect_any_instance_of(my_clazz).to receive(:my_method).with(code, anything).once

但是当我没有传入第二个参数并出现以下错误时,这会失败

     expected: ('first', anything)
          got: ('first')

我知道您可以将不同匹配器的库传递给 with 方法我找不到任何可以以这种方式成为可选的工作。

任何人都可以提供有关如何实现这一点的见解吗?

【问题讨论】:

  • rspec 跟踪器上的这个issue 暗示目前没有特别简单的方法可以做到这一点
  • 从那个问题看来,你是对的。可能需要观察并等待问题得到解决。感谢您的链接

标签: ruby-on-rails ruby rspec


【解决方案1】:

试试这个:

example do
  klass = Class.new

  expect_any_instance_of(klass).to receive(:my_method).at_least(:once) do |instance, arg_1, *|
    expect(arg_1).to eq('first')
  end

  instance = klass.new
  instance.my_method('first')
  instance.my_method('first', second: 'value')
end

但请注意,我们建议不要使用 any_instance 功能:https://relishapp.com/rspec/rspec-mocks/v/3-0/docs/working-with-legacy-code/any-instance

【讨论】:

  • 没有效果,和之前一样。我刚刚意识到我使用的是expect_any_instance_of,这有什么不同。更新了我的问题
  • 仍然中断。一些与使用块有关的事情确实会在之后直接破坏测试。我想我得等待改进的语法
  • 好的,我终于弄清楚了发生了什么。在此处添加一个块正在替换我的 my_method 的实现,以便它永远不会返回预期值。在我的例子中,my_method 是一个填充响应主体的助手,而不是 JSON,它只是返回 true 作为 expect 调用的结果。因此,为什么我的测试会因为 Rack 将这个主体作为错误类型抛出而中断。知道为什么会这样做吗?
  • 我看到有一种方法 and_call_original 可以调用原始方法,但是我如何在您的示例中使用该块?
  • 我建议你重新设计你的代码,这样它就不需要使用如此脆弱的模拟来测试它了。或者通过集成测试对其进行测试。
【解决方案2】:

最简单的解决方案:

expect(my_instance).to receive(:my_method) do |first_param,other_param|
  expect(first_param).to eq(code)
end

这将使您在两种情况下都匹配。

【讨论】:

  • 这对我不起作用。我正在使用 Sinatra,而我正在将应用程序处理传递给 first_param' and the actual value being passing into other_param`。如果我解决了这个问题,在开始抛出错误之后,使用这种风格似乎会混淆执行范围作为代码。
  • 发现另一个与此相关的 RSpec 问题,但实际上并没有有效的解决方案(我可以开始工作)github.com/rspec/rspec-mocks/issues/377
  • 这很奇怪,我经常使用这种匹配方式,从未见过它会导致其他副作用。你确定匹配器在这里引起了问题吗?
  • 当然。在此之后,我调用了一个附加到我的一些示例的 lambda,并使用该块以某种方式使其变砖
【解决方案3】:

避免存根响应,你应该添加'and_call_original'方法:

expect(my_instance).to receive(:my_method) do |first_param,other_param|
  expect(first_param).to eq(code)
end.and_call_original

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-08-23
    • 2012-03-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多