我已经从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的随机排序,但这种情况与谷物有关。我宁愿让它尽可能随机化。
有什么想法吗?
答案 0 :(得分:2)
另一种解决方案是模拟current
和today
方法,并使用它们进行测试。例如:
# 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
我不能真的推荐这个;我倾向于拆分这个规范并按照你的建议单独运行它。