简体   繁体   English

RSpec 剔除 Date.today 以测试方法

[英]RSpec Stubbing out Date.today in order to test a method

I want to test a method that follows one path if the current date is between Jan 1st - Aug 1st, or it follows another path if the current date is between Aug 2nd - December 31st.如果当前日期在 1 月 1 日至 8 月 1之间,我想测试一种遵循一条路径的方法,或者如果当前日期在 8 月 2 日至 12 月 31之间,则它遵循另一条路径。 example:例子:

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

As you can see: return_something_based_on_current_date depends heavily upon Date.today , as does the private methods it invokes.如您所见: return_something_based_on_current_date严重依赖Date.today ,它调用的私有方法也是如此。 This is making it difficult to test both paths within this method since Date.today dynamically returns the current date.这使得在此方法中测试两个路径变得困难,因为Date.today动态返回当前日期。

For testing purposes: I need Date.today to return a static date that I want it to so that I can test that each path is working correctly.出于测试目的:我需要Date.today返回我想要的静态日期,以便我可以测试每个路径是否正常工作。

  • I need to test that the path works correctly if the current date is between Jan 1 - Aug 1如果当前日期在 1 月 1 日至 8 月 1 日之间,我需要测试路径是否正常工作
  • I need to test that the path works correctly if the current date is after Aug 1st.如果当前日期在 8 月 1 日之后,我需要测试路径是否正常工作。

Question : Is there a way that I can make Date.today return a value that I make up within my spec?问题:有什么方法可以让Date.today返回我在规范中构成的值? After the specs that test the return_something_based_on_current_date : I want the dynamic implementation of Date.today to go back to its usual implementation.在测试return_something_based_on_current_date的规范之后:我希望Date.today的动态实现回到其通常的实现。 I just need control over Date.today to test this method.我只需要控制Date.today来测试这个方法。

Add this to your before block .将此添加到您的 before block

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

I *think* it is not necessary to unstub.我*认为*没有必要取消存根。

I recommend you look at the Timecop gem, it allows to freeze the time at a given date.我建议您查看 Timecop gem,它允许在给定日期冻结时间。

On top of stubbing the current Time, it also allows to travel in time for a given test除了存根当前时间之外,它还允许为给定的测试及时旅行

https://github.com/travisjeffery/timecop 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

Update更新

As Andy mentions in the comments, there is a helper method travel_to available since Rails 4.1正如安迪在评论中提到的,自 Rails 4.1 以来,有一个辅助方法travel_to可用

Reference is available here: http://api.rubyonrails.org/classes/ActiveSupport/Testing/TimeHelpers.html可在此处获得参考: http : //api.rubyonrails.org/classes/ActiveSupport/Testing/TimeHelpers.html

There's another approach you might want to consider, that doesn't require any stubbing – change the public method to accept an argument for the current date.您可能需要考虑另一种方法,它不需要任何存根——更改公共方法以接受当前日期的参数。

Clarification:澄清:

Change def return_something_based_on_current_date to def return_something_based_on_current_date(current_date) , then change all instances of Date.today to current_date .更改def return_something_based_on_current_datedef return_something_based_on_current_date(current_date)然后更改的所有实例Date.todaycurrent_date You'll also need to pass current_date into the private methods.您还需要将current_date传递给私有方法。

Then in your tests, you can pass whatever you want as current_date .然后在你的测试中,你可以通过任何你想要的作为current_date

I was in a similar situation but I didn't want to install the gem.我处于类似的情况,但我不想安装 gem。 as I was interested in time intervals bigger than one day so I decided to do it this way因为我对大于一天的时间间隔感兴趣所以我决定这样做

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

so I just tested the expected date, I am afraid that there is a specific time of the day that the test will be broken but I don't care所以我只是测试了预期日期,我担心一天中会有特定时间测试会被破坏但我不在乎

Since Rails 4.2 there's the ActiveSupport::Testing::TimeHelpers module that provides a straightforward way to do this:从 Rails 4.2 开始, ActiveSupport::Testing::TimeHelpers模块提供了一种简单的方法来做到这一点:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM