Mocha:具有特定参数的存根方法,但不包含其他参数

时间:2013-05-15 07:38:39

标签: ruby-on-rails mocha testunit

我想在给定特定参数值时使用Mocha存根方法,并在给出任何其他值时调用原始方法。

当我这样做的时候:

MyClass.any_instance.stubs(:show?).with(:wanne_show).returns(true)

我得到了

unexpected invocation for MyClass.show?(:other_value)

我也知道,在没有'with'调用的情况下编写模拟时我可以存根所有参数,然后给出我特定的模拟。但是我必须知道每次调用的返回值,但事实并非如此:/

tldr; 有没有办法在存根中调用原始方法或只存储特定参数并留下其他参数?

2 个答案:

答案 0 :(得分:1)

答案取决于你正在测试的是什么。

一些注意事项:

1)我总是避免使用stubs.any_instance。您可以在您的存根/模拟中具体,这可以防止错误的测试结果。

2)我更喜欢使用间谍和存根,以主动断言已经调用了某些东西。为此,我们使用bourne gem。另一种方法是使用mock,它会隐式测试是否正在调用某些内容(例如,如果没有被调用则会失败。

所以你的类方法可能看起来像这样(注意,这是RSpec语法):

require 'bourne'
require 'mocha'

it 'calls MyClass.show?(method_params)' do
  MyClass.stubs(:show?)

  AnotherClass.method_which_calls_my_class

  expect(MyClass).to have_received(:show?).with('parameter!')
end

class AnotherClass
  def self.method_which_calls_my_class
    MyClass.show?('parameter!')
  end
end

有很多存根/间谍示例here

希望这有帮助。

答案 1 :(得分:1)

我今天花了一个小时试图让 Mocha 允许我只存根一个特定的会话变量,但失败了,Rspec allows with ease 的方式。虽然我无法找到一种方法来完成这项工作,但我确实找到了一种可能对某些人有所帮助的黑客解决方法,具体取决于具体情况。

我的“解决方案”是在获取目标实例变量后删除会话存根:

ActionDispatch::Request::Session.any_instance.stubs(:delete).returns(state).then.returns(nonce).then.with do |sym|
  ActionDispatch::Request::Session.any_instance.unstub(:delete) if sym == :login_nonce
  true
end

我在这里使用的技巧是,通过知道将在为特定操作进行的前两次调用中传递给 session.delete 的参数,我可以在第二次 delete 之后删除存根调用(对于 login_nonce),因此会话再次开始正常运行。

像这样构造 with 块的另一个潜在有用的方面是该块具有调用者的完整上下文,因此可以直接检查或提取块内的会话内容。也就是说,如果您想要一个测试来获取 blah 会话密钥的值,您应该能够编写类似

ActionDispatch::Request::Session.any_instance.stubs(:[]).with do |key|
  @blah = session[key] if key == :blah
  true
end

据我所知,with 块总是必须返回 true,否则 Mocha 会抛出一个 Minitest::Assertion: unexpected invocation 异常,因为它不知道如果它存根了一个方法,但是传入的参数与它可以处理的参数不匹配。基本问题似乎是,一旦在 stubs 上调用 any_instance,您就不能再让 Mocha 从实际的 session 实例返回值(与 Rspec 不同,它允许回退到使用 and_call_original 的原始对象,如上面链接的答案)。

希望有人可以在未来利用其中的一些想法来形成更优雅的答案,但由于近 8 年过去了而且没有答案,我认为这可能是一个可用的起点。