使用和不需要ActiveSupport进行单元测试

时间:2013-06-07 13:31:04

标签: ruby testing rspec

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

该课程做了一些简单的日期计算。它不依赖于Rails,但由于它始于Rails应用程序,并且仍然在那里使用,它可以使用ActiveSupport的时区感知方法。但是,如果ActiveSupport不可用,则应使用std-lib Date方法。

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

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

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

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

我还可以将规格拆分为两个文件,然后单独运行,但是再次,这似乎是不必要的。

我也可以禁用rspec的随机排序,但这种情况与谷物有关。我宁愿让它尽可能随机化。

有什么想法吗?

2 个答案:

答案 0 :(得分:2)

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

# 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运行会导致测试通过。

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

答案 1 :(得分: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

我不能真的推荐这个;我倾向于拆分这个规范并按照你的建议单独运行它。