RSpec允许我选择带有匹配器的模拟吗?

我打了很多电话

Kernel.open(url).read

在一些遗留代码中,我试图在大规模重构之前对其进行模拟以进行特性测试。

我不喜欢参数被忽略的方式

allow_any_instance_of(Kernel).to(receive_message_chain(:open,:read)
    .and_return(return_value))

所以我替换为

def stub_kernel_open_read(args: '[arg1,arg2,k: v,etc]',returning:)
  allow_any_instance_of(Kernel).to(receive(:open).with(*args)).and_return(double.tap { |d|
    allow(d).to(receive(:read)).and_return(returning)
  })
end

但是我发现我遇到了这些错误:

       "http://my-fake-server/whatever" received :open with unexpected arguments
     expected: ("http://my-fake-server/whatever",{:http_basic_authentication=>["asdf","asdf"]})
          got: ({:http_basic_authentication=>["asdf","asdf"]})
   Diff:
   @@ -1,3 +1,2 @@
   -["http://my-fake-server/whatever",- {:http_basic_authentication=>["asdf","asdf"]}]
   +[{:http_basic_authentication=>["asdf","asdf"]}]

    Please stub a default value first if message might be received with other args as well. 

所以我发现,如果我将存根扩展到此:

allow_any_instance_of(Kernel).to(receive(:open).with(*args)) { |instance|
  return double.tap { |d|
    allow(d).to(receive(:read)) {
      return returning
    }
  }
}

然后instance具有URL的值。就目前而言,这很好,我可以列出允许的URL列表,但感觉很糟糕。

有没有类似的东西

allow_any_instance_of(Kernel).that(eq('http://whatever')).to(receive(:open))

还是我只是在错误的小巷里吠叫?

很显然,我可以使用全局搜索替换来包装Kernel.open(url).read代码,并正确地模拟该全局代码,但我希望尽可能避免这种情况。

mario_l 回答:RSpec允许我选择带有匹配器的模拟吗?

AFAIU您的问题正确无误,您需要类似的内容,以告知模拟游戏“正常”运行:

allow(Kernel).to receive(:open).with(url).and_return(stub)
allow(Kernel).to receive(:open).with(anything).and_call_original # I can't check now,but there's a chance this one should go first,but I doubt it

然后

allow(stub).to receive(:read).and_return('something')

如果您必须模拟Kernel.open以获得更多URL,它会变得有些混乱,但原理是相同的

allow(Kernel).to receive(:open).with(first_url).and_return(first_stub)
allow(Kernel).to receive(:open).with(second_url).and_return(second_stub)
allow(Kernel).to receive(:open).with(anything).and_call_original # I can't check now,but there's a chance this one should go first


allow(first_stub).to receive(:read).and_return('something')
allow(second_stub).to receive(:read).and_return('something else')

除非我完全错过了你的问题的重点?

,

我无法在RSpec的模拟系统中找到任何内容来应对'Kernel.open(url)'方法模拟将url作为实例的事实,如果您使用allow_any_instance_of(Kernel).to(receive(:open))。所以我煮了一个大锅,然后意识到我不需要'any_instance_of'位:

def stub_kernel_open_read(url: 'fake://your_url_parameter_is_wrong',args: ['arg1','arg2',k: :v_etc],**rest)
  allow(Kernel).to(receive(:open).with(*([url] + args)).and_return(reading_double(rest)))
end

def reading_double(return_or_raise)
  double.tap do |d|
    if return_or_raise[:returning]
      allow(d).to(receive(:read).and_return(return_or_raise[:returning]))
    else
      allow(d).to(receive(:read).and_raise(return_or_raise[:raising]))
    end
  end
end

此代码源自尝试删除使用“ any_instance”的receive_message_chain

哦,我遇到各种奇怪的诡计,试图用(*a,**b)参数对任何方法进行存根,尽管这似乎对我尝试烹饪的玩具示例有用,所以我不知道发生了什么。正是这种荒唐的废话让我不喜欢Ruby和鸭式打字。

本文链接:https://www.f2er.com/3108248.html

大家都在问