9

When I want to verify that mock is send expected arguments, I can do

@mock.expect(:fnc, nil, ["a, "b"])

however, if class I want to mock looks like this

class Foo
    def fnc a:, b:
    end
end

how can I mock it and verify values passed as a:, b:?

graywolf
  • 7,092
  • 7
  • 53
  • 77

3 Answers3

9

Below is a real-world example from my company's codebase:

mailer = MiniTest::Mock.new
mailer.expect :deliver, 123 do |template_name:, data:, to:, subject:|
  true
end
mailer.deliver template_name: "xxx", data: {}, to: [], subject: "yyy"

If you also want to verify arguments' types:

mailer.expect :deliver, 123 do |template_name:, data:, to:, subject:|
  template_name.is_a?(String) &&
    data.is_a?(Hash) &&
    to.is_a?(Array) &&
    subject.is_a?(String) &&
end

Update 2022-05-22

You would get ArgumentError if you use this strategy with Ruby v3.

I have submitted a PR here to fix this issue:

https://github.com/minitest/minitest/pull/908

If you wish to use this feature with Ruby v3, please leave some comments to get project owner's attention.

Update 2022-06-28

minitest supports keyword arguments since v5.16.0

https://github.com/minitest/minitest/blob/master/History.rdoc#5160--2022-06-14-

Weihang Jian
  • 7,826
  • 4
  • 44
  • 55
  • Calling `send` instead of calling a method directly is against the principle of least astonishment. Expect a question "why is it made so" from someone (possibly you) who will read that in production code at some point later. P.S. Consider using `public_send` if you really want to go that way. – Artur INTECH Sep 13 '18 at 19:32
  • 2
    I got confused too and thought there was some meta-magic happening, but imagine the method is really called `deliver` rather than `send` and the example becomes straight-forward: you are just mocking the `deliver` method, and passing a block to verify the expectation rather than letting the mock object verify it with its default implementation. – Marc Jan 11 '19 at 16:53
  • Thanks for the feedback! I have updated my answer by renaming the method, also brought up an issue about Ruby v3. – Weihang Jian May 22 '22 at 04:23
0
require 'minitest/autorun'

class APIClient
  def call; end
end

class APIClientTest < Minitest::Test
  def test_keyword_aguments_expection
    api_client = Minitest::Mock.new
    api_client.expect(:call, true, [{ endpoint_url: 'https://api.test', secret_key: 'test' }])
    api_client.call(endpoint_url: 'https://api.test', secret_key: 'test')
    api_client.verify
  end
end

# Running:
.
Finished in 0.000726s, 1377.5945 runs/s, 0.0000 assertions/s.
1 runs, 0 assertions, 0 failures, 0 errors, 0 skips
[Finished in 0.7s]
Artur INTECH
  • 6,024
  • 2
  • 37
  • 34
-1

based on @nus comment,

class FooTest
  def test_fnc_arguments
    Foo.new.fnc a: "a", b: "b"
    # assert true # optional
  end
end
Warren Le
  • 155
  • 1
  • 6