13

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

当我这样做时:

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

我得到一个

unexpected invocation for MyClass.show?(:other_value)

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

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

4

2 回答 2

2

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

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

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调用 (for 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异常,因为如果它已存根方法但传入的参数与它可以匹配的参数不匹配,它不知道该怎么做处理。根本问题似乎是,一旦调用stubsany_instance您就不能再让 Mocha 从实际session实例返回一个值(与 Rspec 不同,它允许使用and_call_original上面链接的答案中的回退到原始对象)。

希望将来有人可以在其中一些想法的基础上构建一个更优雅的答案,但是由于将近 8 年过去了并且没有答案,我认为这可能是一个可用的起点。

于 2021-03-22T00:52:26.840 回答
-1

The answer depends on what exactly you're testing.

A few notes:

1) I always avoid using stubs.any_instance. You can be specific in your stubs/mocks, which prevents false testing positives.

2) I prefer using spies along with stubs, to actively assert that something has been called. We use the bourne gem for this purpose. The alternative is to use a mock, which implicitly tests if something is being called (e.g. will fail if it doesn't get called.

So your class-method might looks something like this (note, this is RSpec syntax):

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

There are a lot of stub/spy examples here.

Hope this helps.

于 2013-05-16T03:24:07.213 回答