RSpec Stubbing Date.today以测试方法

时间:2016-07-01 18:19:18

标签: ruby-on-rails ruby rspec

如果当前日期在1月1日到8月1日之间,我想测试一个跟随一条路径的方法,或者如果当前日期介于当前日期之后,我想测试另一条路径8月2日 - 12月31日。例如:

def return_something_based_on_current_date
  if date_between_jan_1_and_aug_1?
    return "foo"
  else 
    return "bar"
  end
end

private

def date_between_jan_1_and_aug_1?
  date_range = build_date_range_jan_1_through_aug_1
  date_range === Date.today
end

def build_date_range_jan_1_through_aug_1
  Date.today.beginning_of_year..Date.new(Date.today.year, 8, 1)
end

正如您所看到的那样:return_something_based_on_current_date在很大程度上取决于Date.today,它调用的私有方法也是如此。由于Date.today动态返回当前日期,因此很难在此方法中测试这两个路径。

出于测试目的:我需要Date.today返回我想要的静态日期,以便我可以测试每条路径是否正常工作。

  • 如果当前日期在1月1日至8月1日之间,我需要测试路径是否正常工作
  • 如果当前日期是8月1日之后,我需要测试路径是否正常工作。

问题:有没有办法让Date.today返回我在规格范围内组成的值?在测试return_something_based_on_current_date的规范之后:我希望Date.today的动态实现回到其通常的实现。我只需要控制Date.today来测试这种方法。

5 个答案:

答案 0 :(得分:7)

将此内容添加到block之前。

allow(Date).to receive(:today).and_return Date.new(2001,2,3)

我认为*没有必要取消存储。

答案 1 :(得分:3)

我建议您查看Timecop gem,它允许冻结给定日期的时间。

除了存在当前时间之外,它还允许在给定测试的时间内传播

https://github.com/travisjeffery/timecop

describe "some set of tests to mock" do
  before do
    Timecop.freeze(Time.local(1990))
  end

  after do
    Timecop.return
  end

  it "should do blah blah blah" do
  end
end

<强>更新

正如Andy在评论中提到的,自Rails 4.1以来有一种帮助方法travel_to

参考资料如下: http://api.rubyonrails.org/classes/ActiveSupport/Testing/TimeHelpers.html

答案 2 :(得分:0)

您可能需要考虑另一种方法,即不需要任何存根 - 更改公共方法以接受当前日期的参数。

澄清:

def return_something_based_on_current_date更改为def return_something_based_on_current_date(current_date),然后将Date.today的所有实例更改为current_date。您还需要将current_date传递给私有方法。

然后在您的测试中,您可以将所需的任何内容传递给current_date

答案 3 :(得分:0)

我处于类似情况,但我不想安装gem。因为我对大于一天的时间间隔感兴趣,所以我决定采用这种方式

it 'Creates an event for tomorrow' do
  event = FactoryBot.create(:event, :tomorrow)
  expect(event.date.day).to eq (Time.now + 1.day).day
end

it 'Creates an event for the next week' do
  event = FactoryBot.create(:event, :next_week)
  expect(event.date.day).to eq (Time.now + 1.week).day
end

it 'Creates an event for the next month' do
  event = FactoryBot.create(:event, :next_month)
  expect(event.date.day).to eq (Time.now + 1.month).day
end

所以我只是测试了预期的日期,所以恐怕一天中的某个特定时间测试会被破坏,但我不在乎

答案 4 :(得分:0)

从Rails 4.2开始,ActiveSupport::Testing::TimeHelpers模块提供了一种简单的方法:

travel_to(Time.parse("2019-01-19")) do
  # your code here
end