【问题标题】:RSpec Stubbing out Date.today in order to test a methodRSpec 存根 Date.today 以测试方法
【发布时间】:2016-11-04 05:43:20
【问题描述】:

如果当前日期介于 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 来测试这个方法。

【问题讨论】:

标签: ruby-on-rails ruby rspec


【解决方案1】:

将此添加到您之前的@​​987654321@。

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

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

【讨论】:

  • 感谢您的回复。请检查我的小修改。
  • 我在您的答案中添加了示例场景。编辑是您的答案。抱歉,我不是很清楚。
【解决方案2】:

我建议您查看 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 在 cmets 中提到的,自 Rails 4.1 起就有一个辅助方法 travel_to 可用

此处提供参考: http://api.rubyonrails.org/classes/ActiveSupport/Testing/TimeHelpers.html

【讨论】:

  • Rails 4.1 中添加的 travel_to 帮助器在大多数情况下都不需要 Timecop。 brandonhilkert.com/blog/rails-4-1-travel-to-test-helper
  • @AndyWaite 谢谢,我第一次听说。我从版本 1 开始使用 Rails,很容易忽略这种添加到框架中的功能。我会把它添加到帖子中。
【解决方案3】:

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

澄清:

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

然后在你的测试中,你可以传递任何你想要的作为current_date

【讨论】:

  • 你能举个例子吗?我不太清楚你的意思。
【解决方案4】:

我遇到了类似的情况,但我不想安装 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

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

【讨论】:

    【解决方案5】:

    从 Rails 4.2 开始,ActiveSupport::Testing::TimeHelpers 模块提供了一种简单的方法来执行此操作:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-05-04
      • 2013-09-11
      • 1970-01-01
      • 1970-01-01
      • 2013-01-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多