如何从 Ruby 中的 Mocha 模拟返回动态值

发布于 2024-08-30 11:13:49 字数 813 浏览 7 评论 0原文

我的问题的要点如下:-

我正在用 Ruby 为下面表示为“post_to_embassy”的方法编写一个 Mocha 模拟。为了描述问题,实际方法的作用并不是我们真正关心的。但我需要模拟返回动态值。下面的过程“&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

The gist of my problem is as follows:-

I'm writing a Mocha mock in Ruby for the method represented as "post_to_embassy" below. It is not really our concern, for the purpose of describing the problem, what the actual method does. But I need the mock to return a dynamic value. The proc '&prc' below is executing rightly in place of the actual method. But the "with" method in Mocha only allows for boolean values to be returned. So the code below outputs nil. I need it to output the value being passed through orderInfoXml. Does anyone know of an alternate method I can use?

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")

output:-

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

三生路 2024-09-06 11:13:49

我不确定是否有一个完美的方法。但为了让生活更轻松,而不是存根每个可能的响应(如另一个答案中所述),您可以使用 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)。但是,您不必取消每个期望,这会给您很大的自由。

I'm not sure if there is a perfect method for this. But to make life easier, than to stubbing each possible response (as described in another answer), you could go with Mocha's yields method.

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

outputs:

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

This is from the mocked proc:-
foo
foo

This will require you to assign the return of your prc, and it's not exactly pretty (imo). But, you don't have to stub out each expectation, which will give you quite a bit of freedom.

空城之時有危險 2024-09-06 11:13:49

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

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

In general, you are normally better off specifying explicit return values in tests. It tends to make tests hard to understand and hard to maintain if you introduce separate logic into determining what value to return.

I would suggest that you either use Expectation#with with suitable ParameterMatchers to explicitly define return values for different parameter values or use the StateMachine functionality.

时常饿 2024-09-06 11:13:49

Mocha 似乎不支持这一点。将其添加到您的 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)

Mocha doesn't appear to support this. Add this to your 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

Then replace the last 4 lines of your test with:

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)
财迷小姐 2024-09-06 11:13:49

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

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."

I haven't found a way to make the output of a mocked method completely dynamic, but if you have a limited, known number of inputs you can get the output to work correctly.

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)

output:

"original: I am the first XML."
"mocked: I am the first XML."
"mocked: I am the second XML."
"mocked: I am the first XML."
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文