15

我的问题的要点如下: -

我正在为下面表示为“post_to_embassy”的方法在 Ruby 中编写 Mocha 模拟。为了描述问题,实际方法的作用并不是我们真正关心的。但我需要模拟返回一个动态值。下面的 proc '&prc' 代替实际方法正确执行。但是 Mocha 中的“with”方法只允许返回布尔值。所以下面的代码输出 nil。我需要它来输出通过 orderInfoXml 传递的值。有谁知道我可以使用的替代方法?

require 'rubygems'
require 'mocha'
include Mocha::API

class EmbassyInterface 
  def post_to_embassy(xml)
    puts "This is from the original class:-"
    puts xml
    return xml
  end
end

orderInfoXml = "I am THE XML"

mock = EmbassyInterface.new
prc = Proc.new do |orderXml| 
  puts "This is from the mocked proc:-"
  puts orderXml
  orderXml
end

mock.stubs(:post_to_embassy).with(&prc)
mock_result = mock.post_to_embassy(orderInfoXml)
p mock_result
#p prc.call("asd")

输出:-

This is from the mocked proc:-
I am THE XML
nil
4

4 回答 4

5

我不确定是否有完美的方法。但是为了让生活更轻松,而不是对每个可能的响应进行存根(如另一个答案中所述),您可以使用 Mocha 的yields方法。

require "rubygems"
require "mocha"

include Mocha::API

class EmbassyInterface

  def post_to_embassy(xml)
    puts "This is form the original class:-"
    puts xml
    xml
  end
end

order_info_xml = "I am the xml"

mock = EmbassyInterface.new

prc = Proc.new do |order_xml|
  puts "This is from the mocked proc:-"
  puts order_xml
  order_xml
end

mock.stubs(:post_to_embassy).yields prc

prc_return = nil

mock.post_to_embassy { |value| prc_return = value.call("hello world") }
puts prc_return

mock.post_to_embassy { |value| prc_return = value.call("foo") }
puts prc_return

输出:

This is from the mocked proc:-
hello world
hello world

This is from the mocked proc:-
foo
foo

这将要求您分配您的 prc 的回报,而且它并不完全漂亮(imo)。但是,你不必放弃每个期望,这会给你很大的自由。

于 2010-07-23T05:12:43.027 回答
4

摩卡似乎不支持这一点。将此添加到您的 test_helper.rb:

# Replace klass's method_name with method_implementation
def stub_replace(klass, method_name, &method_implementation)
  klass.singleton_class.send(:alias_method, "#{method_name}_mock_backup", method_name)
  klass.define_singleton_method(method_name, method_implementation)
end

def undo_stub_replace(klass, method_name)
  klass.singleton_class.send(:alias_method, method_name, "#{method_name}_mock_backup")
end

然后将测试的最后 4 行替换为:

stub_replace(EmbassyInterface, :post_to_embassy, &prc)
mock_result = mock.post_to_embassy(orderInfoXml)
p mock_result

# cleanup
undo_stub_replace(EmbassyInterface, :post_to_embassy)
于 2015-10-11T17:05:03.870 回答
3

通常,您最好在测试中明确指定返回值。如果您引入单独的逻辑来确定要返回的值,它往往会使测试难以理解和维护。

我建议您使用Expectation#with和合适的ParameterMatchers来明确定义不同参数值的返回值,或者使用StateMachine功能。

于 2010-09-26T16:43:45.153 回答
0

我还没有找到使模拟方法的输出完全动态的方法,但是如果您的输入数量有限且已知,则可以使输出正常工作。

require 'rubygems'
require 'mocha'
include Mocha::API

class EmbassyInterface 
  def post_to_embassy(xml)
    "original: #{xml}"
  end
end

to_mock = EmbassyInterface.new
orderInfoXml1 = "I am the first XML."
orderInfoXml2 = "I am the second XML."

p to_mock.post_to_embassy(orderInfoXml1)

prc = Proc.new do |xml| 
  "mocked: #{xml}"
end
to_mock.stubs(:post_to_embassy).with(orderInfoXml1).returns(prc.call(orderInfoXml1))
to_mock.stubs(:post_to_embassy).with(orderInfoXml2).returns(prc.call(orderInfoXml2))

p to_mock.post_to_embassy(orderInfoXml1)
p to_mock.post_to_embassy(orderInfoXml2)
p to_mock.post_to_embassy(orderInfoXml1)

输出:

"original: I am the first XML."
"mocked: I am the first XML."
"mocked: I am the second XML."
"mocked: I am the first XML."
于 2010-05-20T14:42:47.593 回答