Search code examples
rubymockingminitest

Minitest Mock#expect won't accept fourth (keyword) parameter


I'm trying to use Minitest mocks to verify a call to a method that expects keyword arguments; but, I'm getting this error:

ArgumentError: wrong number of arguments (given 4, expected 2..3)

This is my complete test:

  test ".toggle updates the category" do
    mock = Minitest::Mock.new
    mock.expect :update!, nil, [], {collapsed: true}
    CategoryAnalyzer.toggle_category(mock, true)
    mock.verify
  end

This is the method under test:

  def self.toggle_category(category, collapsed)
    category.update!(collapsed: collapsed)
  end

I see from minitest - mock - expect keyword arguments that Minitest should accept keyword arguments. Is my test set up wrong? Do I somehow have an old version of Minitest? (My Gemfile.lock lists minitest (5.18.0)) Any idea of what else I should check?


Solution

  • https://rubyreferences.github.io/rubychanges/3.0.html#keyword-arguments-are-now-fully-separated-from-positional-arguments

    This is how you're calling expect, with 4 arguments:

    #           1         2    3   4
    mock.expect :update!, nil, [], {collapsed: true}
    

    This is what it expects:

    #          1     2       3          keywords  block
    def expect name, retval, args = [], **kwargs, &blk
    

    Since ruby v3.0 {collapsed: true} is a positional argument. To turn it into keywords, you have to ** splat or just drop the braces:

    #           1         2    3   keywords
    mock.expect :update!, nil, [], collapsed: true
    
    # or this
    mock.expect :update!, nil, [], **{collapsed: true}
    kw = {collapsed: true}
    mock.expect :update!, nil, [], **kw
    

    A simple demo:

    def arg_or_kwarg(one = nil, two = nil, **kwargs)
      {one: one, two: two, kwargs: kwargs}
    end
    
    # pass argument #1
    >> arg_or_kwarg({hash: :arg})
    => {:one=>{:hash=>:arg}, :two=>nil, :kwargs=>{}}
    
    # pass keyword argument
    >> arg_or_kwarg(kw: :arg)
    => {:one=>nil, :two=>nil, :kwargs=>{:kw=>:arg}}