-->

How to assert certain method is called with Ruby m

2019-02-08 01:58发布

问题:

I want to test whether a function invokes other functions properly with minitest Ruby, but I cannot find a proper assert to test from the doc.

The source code
class SomeClass
  def invoke_function(name)
    name == "right" ? right () : wrong ()
  end

  def right
    #...
  end

  def wrong
    #...
  end
end
The test code:
describe SomeClass do
  it "should invoke right function" do
    # assert right() is called
  end

  it "should invoke other function" do
    # assert wrong() is called
  end
end

回答1:

With minitest you use expect method to set the expectation for a method to be called on a mock object like so

obj = MiniTest::Mock.new
obj.expect :right

If you want to set expectation with parameters and return values then:

obj.expect :right, return_value, parameters

And for the concrete object like so:

obj = SomeClass.new
assert_send([obj, :right, *parameters])


回答2:

Minitest has a special .expect :call for checking if some method is called.

describe SomeClass do
  it "should invoke right function" do
    mocked_method = MiniTest::Mock.new
    mocked_method.expect :call, return_value, []
    some_instance = SomeClass.new
    some_instance.stub :right, mocked_method do
      some_instance.invoke_function("right")
    end
    mocked_method.verify
  end
end

Unfortunately this feature is not documented very well. I found about it from here: https://github.com/seattlerb/minitest/issues/216



回答3:

According to the given example, there is no other delegate class, and you want to make sure the method is called properly from the same class. Then below code snippet should work:

class SomeTest < Minitest::Test
  def setup
    @obj = SomeClass.new
  end

  def test_right_method_is_called
    @obj.stub :right, true do
      @obj.stub :wrong, false do
        assert(@obj.invoke_function('right'))
      end
    end
  end

  def test_wrong_method_is_called
    @obj.stub :right, false do
      @obj.stub :wrong, true do
        assert(@obj.invoke_function('other'))
      end
    end
  end
end

The idea is to stub [method_expect_to_be_called] by returning a simple true value, and in the stub block assert it's indeed being called and returning the true value. To stub the other unexpected method is just to make sure that it's not being called.

Note: assert_send won't work correctly. Please refer to official doc.

In fact, below statement will pass, but doesn't mean it's working as expected:

assert_send([obj, :invoke_function, 'right'])
# it's just calling invoke_function method, but not verifying any method is being called