2

我有一个 Ruby 程序在运行时失败,但是当我用 RSpec 测试它时可以工作。我知道错误的原因以及如何修复它(见下文),但我不知道如何构建一个失败的 RSpec 测试来证明错误的存在。

想象一下下面的 Ruby:

foob​​ar.rb

class Foobar
  attr_reader :fruit
  def initialize
    @fruit = Set.new ["Apple", "Banana", "Kiwi"]
  end
end

上面的代码使用了Set,但它没有“要求 'set'”。这会导致它在运行时失败:

$ irb
> require './foobar.rb'
> f = Foobar.new
NameError: uninitialized constant Foobar::Set

在修复疏忽之前,我想构建一个简单的 RSpec 测试来证明这个错误。我的测试如下所示:

foob​​ar_spec.rb

require 'rspec'
require './foobar.rb'

describe Foobar do
  it "can be initialized" do
    expect { Foobar.new }.to_not raise_error
  end
end

运行测试,我惊讶地发现它通过了:

$ rspec foobar_spec.rb
.

Finished in 0.00198 seconds
1 example, 0 failures

经过一番挖掘,我了解到 RSpec 会为自己加载Set。这导致Set可用于它测试的代码,在我的例子中隐藏了一个错误。

在我的测试中,我有“卸载/不需要”设置的想法。我最接近的是这段代码:

Object.send(:remove_const, :Set)

这确实会导致测试失败,但不幸的是,它也阻止了 Set 被未来的“require”再次加载,这意味着即使我在 foobar.rb 中添加了require 'set' ,它仍然会失败。

有没有更好的方法在运行时卸载 gem?如果没有,我该怎么做才能使这个测试失败?

4

1 回答 1

3
require 'rspec'

describe 'foobar.rb' do
  it "can instantiate Foobar" do
    `ruby -e 'Foobar.new' -r./foobar.rb`
    $?.exitstatus.should == 0
  end
end

适用于您提到的一种情况。也就是说,我不会推荐这种方法。为了涵盖引用类的所有情况,您需要以这种方式运行所有规范,因为类引用可能出现在代码中的任何位置。

于 2012-12-04T09:49:59.930 回答