在Ruby单元测试中模拟丢失的gem

时间:2010-04-23 08:20:34

标签: ruby unit-testing rubygems

有没有办法模拟某些单元测试缺少某个gem,缺少实际卸载然后在测试期间重新安装gem?

我正在编写命令行实用程序,并希望确保我的测试涵盖用户可能没有我支持的所有宝石的情况。例如,我正在使用fsevents - 一个特定于Leopard的用于监视文件系统事件的包 - 它永远不会出现在其他系统上,以及一个纯粹可选的咆哮宝石。

4 个答案:

答案 0 :(得分:2)

我曾经使用过我写的名为with_constant_unavailable的方法。我忘记了确切的细节,但我认为它是这样的:

def with_constant_unavailable(constant_name, &block)
  match_data = constant_name.to_s.match(/(?:(.+)::)?(.+)/)
  if match_data[2]
    owning_module, constant_name = match_data[1].constantize, match_data[2]
  else
    owning_module, constant_name = Object, constant_name.to_s
  end
  original_constant = owning_module.send :remove_const, constant_name
  begin
    yield
  ensure
    owning_module.const_set constant_name, original_constant
  end
end

然后你可以像这样进行测试:

def test_uses_foo_when_bar_unavailable
  with_constant_unavailable(Bar) do
    assert baz.quux == Foo
  end
end

答案 1 :(得分:1)

您可以测试常量的存在。

if !defined?(Growl)
  ...
end

在测试中,您可以临时rename/disable/remove常量来模拟丢失的库。

答案 2 :(得分:1)

我会尝试重置gem路径,例如:

require 'rubygems' 
Gem.clear_paths 
ENV['GEM_HOME'] = "" 
ENV['GEM_PATH'] = "" 

我也会保存它并在之后恢复它。

答案 3 :(得分:0)

一旦你require某事,我认为撤消它是非常困难的。但是,您可以执行的操作是一组单独的测试,这些测试始终在单独的Ruby解释器实例中运行,并将它们作为不同的rake任务调用。所以你可能会有这样的事情:

Rake::TestTask.new(:no_growl_test) do |t|
  t.libs << 'lib'
  t.pattern = 'test/compatibility/no_growl.rb'
end

这个想法是,这将在一个新的,“干净”的环境中运行,在这种环境中你永远无法加载Growl。其他一些用户提出了一些方法,可以让Rubygems找不到有问题的宝石,甚至可以在Gem API中实现。

或者,使用JRuby创建多个不相交的运行环境并不困难,但这对你正在做的事情来说可能有些过分。