如何在Ruby中重置类定义?

时间:2014-08-29 16:22:20

标签: ruby

如何在Ruby中从内存中完全删除类?

我有两个我正在使用的文件:

# foo.rb
require 'expensive_library'

class Foo < ExpensiveLibrary::Plugin
   ...
end

# foo_tests.rb
require 'foo'
require 'test/unit'

class foo_tests < Test::Unit::TestCase
  def test_foo_meets_spec_1
    ...
  end
  def test_foo_meets_deprecated_spec
    ...
  end
end

昂贵的图书馆很贵;加载需要15秒以上。这在开发过程中反复运行测试的时间太长(测试套件的其余部分不到1秒)。

我通过启动Pry并编写一个加载两个文件并调用Test::Unit:Autorunner.run的函数来解决昂贵库的加载时间问题。在第一次测试中,这仍然有15秒的暂停,但后续的测试运行时间不到1秒。

然而,有两个问题:

  1. Pry抱怨重新定义Foo和Foo_tests的所有方法
  2. 当我从源文件中删除一个方法时,它仍然在我的测试环境中定义,导致虚假失败。
  3. 根据其他Stack Overflow问题(例如“How to undefine class in Ruby?”),我尝试调用Object.constants.remove(:Foo)Object.constants.remove(:Foo_tests)。我不再获得方法重新定义的错误,但现在自动运行器多次运行测试,包括删除测试。

    我想要的是在不重新加载ExpensiveLibrary的情况下运行修改后的测试。取消定义测试类是我看到的方式,但我不知道如何。其他解决方案可能会更好。

3 个答案:

答案 0 :(得分:1)

在我看来,您正在寻找的是Spork之类的预加载器,甚至是rspec-preloader之类的更具体的预加载器。使用预加载器时,您必须要求使用“foo”。文件在${variable}文件中,您可能已经拥有该文件:

spec/spec_helper.rb

# spec/spec_helper.rb require 'foo' # ... 应加载整个应用环境。可以说,在一次运行一个测试时,它的成本更高。但是通过使用预加载器,您只需要一次所有代码。

答案 1 :(得分:0)

好的,只是在这里吐痰,因为我不确定你到底想要什么,但你尝试过undef还是undef_method?它们不能直接在类上工作,但是如果你取消调用你不想做的测试的方法,它可能对你有用吗?

答案 2 :(得分:0)

您可以破解加载路径(Adding a directory to $LOAD_PATH (Ruby))。

  • 创建一些文件夹,例如./tests/fake_implementations/
  • 将其添加到$ LOAD_PATHS
  • 使用expensive_library.rb
  • 的轻量级虚假实现添加文件ExpensiveLibrary
  • 然后require 'expensinsive_library'将加载此文件而不是原始文件。