Как подделать Time.now? - PullRequest
       41

Как подделать Time.now?

70 голосов
/ 01 августа 2009

Какой лучший способ установить Time.now для тестирования чувствительных ко времени методов в модульном тесте?

Ответы [ 14 ]

74 голосов
/ 03 августа 2009

Мне действительно нравится библиотека Timecop . Вы можете делать временные деформации в виде блоков (точно так же как временные деформации):

Timecop.travel(6.days.ago) do
  @model = TimeSensitiveMode.new
end
assert @model.times_up!

(Да, вы можете вкладывать путешествия во времени в форме блоков).

Вы также можете сделать декларативное путешествие во времени:

class MyTest < Test::Unit::TestCase
  def setup
    Timecop.travel(...)
  end
  def teardown
    Timecop.return
  end
end

У меня есть несколько огурцов помощников для Timecop здесь . Они позволяют вам делать такие вещи, как:

Given it is currently January 24, 2008
And I go to the new post page
And I fill in "title" with "An old post"
And I fill in "body" with "..."
And I press "Submit"
And we jump in our Delorean and return to the present
When I go to the home page
I should not see "An old post"
42 голосов
/ 01 августа 2009

Лично я предпочитаю делать часы инъекционными, вот так:

def hello(clock=Time)
  puts "the time is now: #{clock.now}"
end

Или:

class MyClass
  attr_writer :clock

  def initialize
    @clock = Time
  end

  def hello
    puts "the time is now: #{@clock.now}"
  end
end

Однако многие предпочитают использовать библиотеку насмешек / заглушек. В RSpec / flexmock вы можете использовать:

Time.stub!(:now).and_return(Time.mktime(1970,1,1))

Или в мокко:

Time.stubs(:now).returns(Time.mktime(1970,1,1))
14 голосов
/ 05 августа 2009

Я использую RSpec, и я сделал это: Time.stub! (: Сейчас) .and_return (2.days.ago) перед вызовом Time.now. Таким образом, я могу контролировать время, которое я использовал для этого конкретного теста

10 голосов
/ 01 августа 2009

Do Time-Warp

time-warp - это библиотека, которая делает то, что вы хотите. Он дает вам метод, который требует времени и блока, а все, что происходит в блоке, использует поддельное время.

pretend_now_is(2000,"jan",1,0) do
  Time.now
end
9 голосов
/ 16 сентября 2015

Используя Rspec 3.2, я нашел единственный простой способ подделать возвращаемое значение Time.now:

now = Time.parse("1969-07-20 20:17:40")
allow(Time).to receive(:now) { now }

Теперь Time.now всегда будет возвращать дату посадки Аполлона-11 на Луну.

Источник: https://www.relishapp.com/rspec/rspec-mocks/docs

7 голосов
/ 03 февраля 2011

Не забывайте, что Time это просто константа, которая относится к объекту класса. Если вы хотите вызвать предупреждение, вы всегда можете сделать

real_time_class = Time
Time = FakeTimeClass
# run test
Time = real_time_class
1 голос
/ 20 июля 2016

Если у вас включен ActiveSupport, вы можете использовать:

travel_to Time.zone.parse('2010-07-05 08:00')

http://api.rubyonrails.org/classes/ActiveSupport/Testing/TimeHelpers.html

1 голос
/ 23 октября 2014

У меня была такая же проблема, мне приходилось подделывать время для спецификации на определенный день, а время просто делало это:

Time.stub!(:now).and_return(Time.mktime(2014,10,22,5,35,28))        

это даст вам:

2014-10-22 05:35:28 -0700
1 голос
/ 04 августа 2009

Также см. этот вопрос , где я также разместил этот комментарий.

В зависимости от того, с чем вы сравниваете Time.now, иногда вы можете изменить свои приборы для достижения той же цели или проверить ту же функцию. Например, у меня была ситуация, когда мне нужно было, чтобы одна вещь случилась, если какое-то свидание было в будущем, а другая - в прошлом. Что я смог сделать, так это включить в мои приборы встроенный рубин (эрб):

future:
    comparing_date: <%= Time.now + 10.years %>
    ...

past:
    comparing_date: <%= Time.now - 10.years %>
    ...

Затем в своих тестах вы выбираете, какой из них использовать для тестирования различных функций или действий в зависимости от времени относительно Time.now.

0 голосов
/ 18 сентября 2013

Недавно выпущенный Test::Redef делает этот и другие подделки простыми даже без реструктуризации кода в стиле внедрения зависимостей (особенно полезно, если вы используете другие люди). 'код.)

fake_time = Time.at(12345) # ~3:30pm UTC Jan 1 1970
Test::Redef.rd 'Time.now' => proc { fake_time } do
   assert_equal 12345, Time.now.to_i
end

Однако, будьте осторожны с другими способами получить время, чтобы оно не выдалось (Date.new, скомпилированное расширение, которое делает свой собственный системный вызов, взаимодействует с такими вещами, как внешние серверы баз данных, которые знают текущие метки времени и т. Д.) Похоже, что приведенная выше библиотека Timecop может преодолеть эти ограничения.

Другие замечательные применения включают в себя тестирование таких вещей, как «что происходит, когда я пытаюсь использовать этот дружественный http-клиент, но он решает вызвать это исключение вместо того, чтобы возвращать мне строку?» без фактической настройки условий сети, которые приводят к этому исключению (что может быть сложно). Он также позволяет проверять аргументы для переопределенных функций.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...