3

我已经从 Rails 应用程序中提取了一个类到gem中。它非常非常简单,但我当然想对其进行全面测试(我正在使用 rspec)。

该类进行了一些简单的日期计算。它不依赖于 Rails,但由于它是在 Rails 应用程序中开始的,并且仍然在那里使用,它尽可能使用 ActiveSupport 的时区感知方法。但是,如果 ActiveSupport 不可用,它应该使用 std-libDate方法。

具体来说,它只在一个地方执行此操作:将可选参数默认为“今天的日期”:

arg ||= if Date.respond_to?(:current)
  Date.current # use ActiveSupport's time zone-aware mixin if possible
else
  Date.today   # stdlib fallback
end

问题是:我如何正确测试这个?如果我需要 ActiveSupport 在我的spec_helper.rb,它显然总是会使用它。如果我在任何地方都不需要它,它就永远不会使用它。如果我需要它用于单个示例组,rspec 的随机执行顺序会使测试变得不可预测,因为我不知道什么时候需要 AS。

我可以before(:all)在嵌套组中要求它,因为嵌套组(我相信)从最高到最深处理。但这似乎非常不雅。

我还可以将规范拆分为两个文件,并分别运行它们,但同样,这似乎没有必要。

我也可以禁用 rspec 的随机排序,但这有点违反规定。我宁愿让它尽可能随机化。

有任何想法吗?

4

2 回答 2

2

另一种解决方案是模拟currentandtoday方法,并使用它们进行测试。例如:

# you won't need these two lines, just there to make script work standalone
require 'rspec'
require 'rspec/mocks/standalone'

def test_method(arg = nil)
    arg ||= if Date.respond_to?(:current)
      Date.current # use ActiveSupport's time zone-aware mixin if possible
    else
      Date.today   # stdlib fallback
    end
    arg
end

describe "test_method" do
    let(:test_date) { Date.new(2001, 2, 3) }
    it "returns arg unchanged if not nil" do
        test_method(34).should == 34
    end

    context "without Date.current available" do
        before(:all) do
            Date.stub(:today) { test_date }
        end
        it "returns Date.today when arg isn't present" do
            test_method.should == test_date
        end
    end

    context "with Date.current available" do
        before(:all) do
            Date.stub(:current) { test_date }
        end
        it "returns Date.current when arg isn't present" do
            test_method.should == test_date
        end
    end
end

rspec test.rb在测试通过的情况下运行。

此外,存根仅存在于每个上下文中,因此规范的运行顺序无关紧要。

于 2013-06-07T14:43:34.763 回答
0

这不仅有点反常,但它应该有效。包括 ActiveSupport,然后:

context "without ActiveSupport's Date.current" do
  before(:each) do
    class Date
      class << self
        alias_method :current_backup, :current
        undef_method :current
      end
    end
  end

  # your test

  after(:each) do
    class Date
      class << self
        alias_method :current, :current_backup
      end
    end
  end
end

我真的不能推荐这个;我更愿意按照您的建议拆分这个规范并单独运行它。

于 2013-06-07T14:06:49.703 回答