如何断言Ruby minitest框架调用了某个方法?

问题描述 投票:0回答:6

我想使用 minitest Ruby 测试一个函数是否正确调用其他函数,但我无法从

doc
中找到合适的 assert 进行测试。

源代码
class SomeClass
  def invoke_function(name)
    name == "right" ? right () : wrong ()
  end

  def right
    #...
  end

  def wrong
    #...
  end
end
测试代码:
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
ruby unit-testing testing minitest
6个回答
31
投票

Minitest 有一个特殊的

.expect :call
用于检查是否调用了某个方法。

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

不幸的是,这个功能没有得到很好的记录。我从这里找到了它:https://github.com/seattlerb/minitest/issues/216


25
投票

使用 minitest,您可以使用

expect
方法来设置对模拟对象调用方法的期望,如下所示

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

如果你想用参数和返回值设置期望,那么:

obj.expect :right, return_value, parameters

对于像这样的具体对象:

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

3
投票

根据给定的示例,没有其他委托类,并且您要确保从同一类正确调用该方法。那么下面的代码片段应该可以工作:

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

这个想法是通过返回一个简单的 true 值来存根 [method_expect_to_be_used],并在存根块中断言它确实被调用并返回 true 值。存根其他意外方法只是为了确保它没有被调用。

注意:assert_send 将无法正常工作。请参考官方文档

事实上,下面的语句会通过,但并不意味着它按预期工作:

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

0
投票

要存根和断言方法调用,请使用

MiniTest::Mock
。有两种使用方法:

  • 存根对象的方法以返回模拟对象,该对象具有存根方法
  • 存根对象的方法来调用模拟方法
test "return the mock object when calling the stubbed method" do
  # the object you want to stub
  obj = Book.new

  mock = MiniTest::Mock.new
  mock.expect :the_method_to_stub, "my cool return value"

  obj.stub :method_that_gives_you_a_mock, mock do
    x = obj.method_that_gives_you_a_mock
    assert_equal x.the_method_to_stub, "my cool return value"
  end

  # assert that the method was called once
  mock.verify
end
test "call the mock method when calling the stubbed method" do
  # the object you want to stub
  obj = Book.new

  mock = MiniTest::Mock.new
  # use :call to make the mock a callable
  mock.expect :call, "my cool return value"

  obj.stub :method_that_calls_the_mock, mock do
    assert_equal obj.method_that_calls_the_mock, "my cool return value"
  end

  # assert that the method was called once
  mock.verify
end

要使用

MiniTest::Mock
,您可能需要添加
require 'minitest/autorun'
来加载 MiniTest 常量。


0
投票

最近我创建了一个 gem,用于缓解这种断言,称为 'stubberry'

这里介绍了如何使用它来管理所需的行为。

首先你需要回答以下问题:

  • 在测试序列之前您是否有权访问原始对象 执行?

  • 有什么间接的方法可以确定通话发生了吗?即,您有权访问的其他对象上应该有一些方法调用。

  • 您是否需要实际调用该方法,或者可以使用正确的对象或可调用的方法对其进行存根吗?

如果您有权访问该对象,并且可以使用可调用对象来存根该方法:

obj.stub_must( :right, -> { stub_response } ) {
  ... do something 
}

如果您有权访问该对象,但不想存根该方法,而只想确保调用该方法:

  assert_method_called( obj, :right ) {
    .... do something with obj
  }

如果您无权访问要测试的对象。 但是您可以使用其他一些对象方法调用进行间接检查,可以说“正确”方法将以 API 调用执行结束:

API.stub_must( :get, -> (path, params) {
  assert_equal( path, :expected_path )
  assert_equal( params, {} )
} ) do
  ... do something  
end
  

如果您无法进行间接检查:


stunt_boudle = Obj.new

stunt_boudle.stub_must( :right, -> () {
  #do needed assertions
} ) do
   Obj.stub_must(:new, stunt_boudle) do 
     # do some integration testing 
   end
end 

# OR use assert_method_called the same way

还有一组很酷的按 id 存根 ActiveRecord 对象,在这种情况下,当您无法在测试操作开始时访问该对象及其 ActiveRecord 对象时,可以使用它们。


0
投票

2024 年 3 月更新:

一般来说,您可以按如下方式进行:

mock = Minitest::Mock.new(delegator)
mock.expect(:delete, 'return value', ['param1'])

其中

delegator
是委托了意外方法的对象。

上述答案与以前版本的 Minitest 的变化:

  • MiniTest
    更改为
    MiniTest
    (注意小写“t”)。
  • Mock#expect
    需要返回值参数。
© www.soinside.com 2019 - 2024. All rights reserved.