Minitest: 如何使用模拟对象进行存根,并验证其参数

4

这里有一个关于如何模拟module Email类方法的微型示例。该方法名为connect_and_send

require 'minitest/autorun'
module Email
  def self.connect_and_send(*args)
    nil
  end
end
class Test < Minitest::Test
  def test_it
    fake = Minitest::Mock.new
    fake.expect :connect_and_send, nil, ['a', 'b', 'c']
    Email.stub :connect_and_send, fake do
      Email.connect_and_send 'a', 'b', 'z'
    end
    fake.verify
  end
end

该示例旨在验证方法是否被调用以及其参数。
但是它会产生一个错误消息,即期望调用connect_and_send,但未被调用!
  1) Error:
Test#test_it:
MockExpectationError: expected connect_and_send("a", "b", "c") => nil
    -:14:in 'test_it'

1 runs, 0 assertions, 0 failures, 1 errors, 0 skips

我原以为会出现错误消息,提示该方法(connect_and_send)给定了不正确的参数。

在使用 Minitest 时,如何使用模拟(mock)进行存根(stub),并验证其参数?

1个回答

7
答案是使用:call方法来调用expect函数,而不是直接调用connect_and_send函数。下面是代码示例:

require 'minitest/autorun'
module Email
  def self.connect_and_send(*args)
    nil
  end
end
class Test < Minitest::Test
  def test_it
    fake = Minitest::Mock.new
    fake.expect :call, nil, ['a', 'b', 'c']
    Email.stub :connect_and_send, fake do
      Email.connect_and_send 'a', 'b', 'z'
    end
    fake.verify
  end
end

验证了传递给connect_and_send方法的参数是否符合要求。

如果存根方法被传递了不正确的参数,则会提供适当的错误消息:

  1) Error:
Test#test_it:
MockExpectationError: mocked method :call called with unexpected arguments ["a", "b", "z"]
    -:12:in 'block in test_it'
    -:11:in 'test_it'

1 runs, 0 assertions, 0 failures, 1 errors, 0 skips

这证明被测试的代码调用了方法connect_and_send

如果一个对象有多个需要存根化并验证其参数的方法,那么请使用多个模拟对象。

这是Minitest关于Object#stub的文档。技术上是正确的,当它在第二个参数中says(参见第三行):

#stub(name, val_or_callable, *block_args) ⇒ Object

的持续时间内添加一个临时的存根化方法来替换name
如果val_or_callable响应#call,则返回调用它的结果[.]

然而,我认为许多人(包括我自己)会误读该短语的文档,将其解释为对存根化方法的“调用”,例如在此示例中的connect_and_send方法。为什么?因为:

  1. 在第三行中,“call”这个词有两个意思;

  2. #call中,哈希符号#略微类似于字母E、H和T,这些都是误读#call所需的所有字母:

无论如何,如果 val_or_callable 响应调用,则返回调用结果。

不管怎样,我认为通过添加“方法”这个词可以改进文档:

如果 val_or_callable 具有#call方法,则返回调用其结果。

对我来说,在Minitest文档中的示例(在Object#stubMock中)可能在模拟和存根结合时显得有些不完整。

再次提醒,当您验证传递给模拟对象的参数时(使用Minitest),您应该使用:call方法来expect,而不是期望您正在存根的方法!


1
有没有办法查看预期参数和接收参数之间的差异? - Ben

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接