Ruby 中的模拟构造函数

发布于 2024-07-04 02:13:29 字数 479 浏览 9 评论 0原文

我是一名 Java 开发人员,正在研究 Ruby,并且很喜欢它。 我了解到,由于 Ruby 的元编程功能,我的单元测试变得更加干净,而且我不需要令人讨厌的模拟框架。 我有一个需要 File 类服务的类,在我的测试中我不想触及我的真实文件系统。 在 Java 中,我会使用一些虚拟文件系统,以便更容易地“接缝”地传递假对象,但在 Ruby 中,这显然是多余的。 与 Java 世界相比,我的研究成果似乎已经非常不错了。 在我的测试类中,我有一个可选的构造函数参数:

def initialize(file_class=File)

当我需要在类中打开文件时,我可以执行以下操作:

@file_class.open(filename)

调用转到真正的文件类,或者在我的单元测试中,它进入一个不接触文件系统的假类。 我知道一定有更好的方法可以通过元编程来做到这一点?

I'm a Java-developer toying with Ruby, and loving it. I have understood that because of Ruby's metaprogramming facilities my unit-tests become much cleaner and I don't need nasty mocking frameworks. I have a class which needs the File class's services and in my test I don't want to touch my real filesystem. In Java I would use some virtual file system for easier "seams" to pass fake-objects in but in Ruby that's obviously overkill. What I come up seems already really nice compared to the Java-world. In my class under test I have an optional constructor parameter:

def initialize(file_class=File)

When I need to open files within my class, I can then do this:

@file_class.open(filename)

And the call goes to either the real File-class, or in case of my unit-test, it goes to a fake-class which doesn't touch the filesystem. I know there must be a better way to do this with metaprogramming?

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

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

发布评论

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

评论(3

笙痞 2024-07-11 02:13:29

Mocha (http://mocha.rubyforge.org/) 是一个非常好的 ruby​​ 模拟库。 根据您实际想要测试的内容(即,如果您想伪造 File.new 调用以避免文件系统依赖性,或者如果您想验证是否将正确的参数传递到 File.new 中),您可以这样做像这样的东西:


require 'mocha'

mock_file_obj = mock("My Mock File") do
  stubs(:some_instance_method).returns("foo")
end

File.stubs(:new).with(is_a(String)).returns(mock_file_obj)

Mocha (http://mocha.rubyforge.org/) is a very good mocking library for ruby. Depending on what you're actually wanting to test (i.e. if you want to just fake out the File.new call to avoid the file system dependency or if you want to verify that the correct arguments are passed into File.new) you could do something like this:


require 'mocha'

mock_file_obj = mock("My Mock File") do
  stubs(:some_instance_method).returns("foo")
end

File.stubs(:new).with(is_a(String)).returns(mock_file_obj)

当爱已成负担 2024-07-11 02:13:29

在您概述的情况下,我建议您所做的事情看起来不错。 我知道这是 James Mead(Mocha 的作者)所提倡的一种技术。 没有必要仅仅为了元编程而进行元编程。 以下是 James 对此的看法(以及您可以尝试的一长串其他技术)

In the case you've outlined, I'd suggest that what you're doing seems fine. I know that it's a technique that James Mead (the author of Mocha) has advocated. There's no need to do metaprogramming just for the sake of it. Here's what James has to say about it (and a long list of other techniques you could try)

十级心震 2024-07-11 02:13:29

这对我来说是一个特别困难的挑战。 在我收到的这个问题的帮助下,代表我做一些额外的工作,这是我找到的解决方案。

# lib/real_thing.rb
class RealThing
  def initialize a, b, c
    # ...
  end
end

# test/test_real_thing.rb
class TestRealThing < MiniTest::Unit::TestCase

  class Fake < RealThing; end

  def test_real_thing_initializer
    fake = mock()
    Fake.expects(:new).with(1, 2, 3).returns(fake)
    assert_equal fake, Fake.new(1, 2, 3)
  end

end

This is a particularly difficult challenge for me. With the help I received on this question, and some extra work on my behalf, here's the solution I arrived at.

# lib/real_thing.rb
class RealThing
  def initialize a, b, c
    # ...
  end
end

# test/test_real_thing.rb
class TestRealThing < MiniTest::Unit::TestCase

  class Fake < RealThing; end

  def test_real_thing_initializer
    fake = mock()
    Fake.expects(:new).with(1, 2, 3).returns(fake)
    assert_equal fake, Fake.new(1, 2, 3)
  end

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