【问题标题】:Mocha: Can I put a "never" expectation on a stubbed method WITH parameters?Mocha:我可以对带有参数的存根方法提出“从不”的期望吗?
【发布时间】:2013-06-25 01:18:29
【问题描述】:

我的问题和这个类似:Mocha: stubbing method with specific parameter but not for other parameters

obj.expects(:do_something).with(:apples).never
perform_action_on_obj

perform_action_on_obj 不会像我预期的那样调用do_something(:apples)。但是,它可能会调用do_something(:bananas)。如果是这样,我会遇到意外的调用失败。

我的理解是,由于我将never 放在期望的末尾,因此它仅适用于特定的修改期望。然而,一旦我开始嘲笑 obj 上的行为,我似乎在某种意义上“搞砸了”。

如何允许在 obj 上调用 do_something 方法的其他方法?

编辑:这是一个清晰的例子,完美地展示了我的问题:

describe 'mocha' do
  it 'drives me nuts' do
    a = mock()
    a.expects(:method_call).with(:apples)

    a.lol(:apples)
    a.lol(:bananas) # throws an unexpected invocation
  end 
end

【问题讨论】:

  • 你需要确定你是否调用 do_something(:bananas) 你有一个 expects(:do_something).with(:bananas)
  • 为什么?为什么 mocha 会“接管”方法调用。一旦我像这样模拟一个方法调用,它就会搞砸一切
  • 我不太了解 - 您是否希望多次调用该方法而不会导致错误,或者您是否试图断言该方法永远不会使用给定参数调用?
  • 两者。我想断言该方法永远不会使用给定参数调用,同时仍允许使用其他参数调用它。

标签: ruby-on-rails ruby-on-rails-3 unit-testing testing mocha.js


【解决方案1】:

这是使用ParameterMatchers 的解决方法:

require 'test/unit'
require 'mocha/setup'

class MyTest < Test::Unit::TestCase
  def test_something
    my_mock = mock()
    my_mock.expects(:blah).with(:apple).never
    my_mock.expects(:blah).with(Not equals :apple).at_least(0)
    my_mock.blah(:pear)
    my_mock.blah(:apple)
  end
end

结果:

>> ruby mocha_test.rb 
Run options: 

# Running tests:

F

Finished tests in 0.000799s, 1251.6240 tests/s, 0.0000 assertions/s.

  1) Failure:
test_something(MyTest) [mocha_test.rb:10]:
unexpected invocation: #<Mock:0xca0e68>.blah(:apple)
unsatisfied expectations:
- expected never, invoked once: #<Mock:0xca0e68>.blah(:apple)
satisfied expectations:
- allowed any number of times, invoked once: #<Mock:0xca0e68>.blah(Not(:apple))


1 tests, 0 assertions, 1 failures, 0 errors, 0 skips

总的来说,我同意你的看法:这种行为令人沮丧,并且违反了最小意外原则。也很难将上述技巧扩展到更一般的情况,因为您必须编写一个越来越复杂的“catchall”表达式。如果您想要更直观的东西,我觉得RSpec's mocks 非常好。

【讨论】:

  • 不错。这让我解决了这个问题,但肯定一点也不优雅!
【解决方案2】:

你试过block feature of with吗?

鉴于此:

obj.stubs(:do_something).with(:apples)

给出与此相同的行为:

obj.stubs(:do_something).with { |p| p == :apples }

你可以翻转逻辑得到你想要的:

obj.stubs(:do_something).with { |p| p != :apples }

使用:apples 以外的任何内容调用do_something 将通过,而obj.do_something(:apples) 将产生意外调用。

【讨论】:

    【解决方案3】:

    这更像是一个 hack,而不是解释 mocha 行为的真正答案,但也许以下内容会起作用?

    obj.expects(:do_something).with(:apples).times(0)
    

    Mocha 将使用times rather than exactly 设置基数实例变量。

    【讨论】:

    • 啊不幸的是,当调用obj.do_something(:bananas) 时会导致同样的意外调用错误
    • 坚果。是的,我没有更好的主意。 Mocha 源代码中的某处有答案,但expects(:do_something).with(:bananas) 可能更容易
    【解决方案4】:

    接受的答案对我不起作用,所以我想出了这个解决方法。

    class NeverError < StandardError; end
    
    obj.stubs(:do_something).with(:apples).raises(NeverError)
    
    obj.do_something(:bananas)
    
    begin
      obj.do_something(:apples)
    rescue NeverError
      assert false, "expected not to receive do_something with apples"
    end
    

    还有改进的余地,但这给出了要点并且应该很容易修改以适应大多数情况。

    【讨论】:

      猜你喜欢
      • 2013-01-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-02-21
      • 2014-05-05
      • 2011-08-23
      • 1970-01-01
      • 2018-04-15
      相关资源
      最近更新 更多