32

我想测试一个函数是否使用 minitest Ruby 正确调用其他函数,但我无法从docassert中找到合适的测试对象。

源代码
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
4

4 回答 4

26

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

于 2015-03-14T13:20:26.860 回答
25

使用 minitest,您可以使用expect方法来设置要在模拟对象上调用的方法的期望,如下所示

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

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

obj.expect :right, return_value, parameters

对于像这样的具体对象:

obj = SomeClass.new
assert_send([obj, :right, *parameters])
于 2012-06-03T10:20:15.540 回答
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

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

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

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

assert_send([obj, :invoke_function, 'right'])
# it's just calling invoke_function method, but not verifying any method is being called
于 2015-08-13T10:10:58.427 回答
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 对象时,您可以在这种情况下使用它们。

于 2022-01-18T07:55:14.177 回答