Was ist der beste Weg, Time.now
für den Test von zeitempfindlichen Methoden in einem Komponententest einzustellen?Wie man Time.now vortäuscht?
Antwort
die
Zeitverzerrungs time-warp Sie ist eine Bibliothek, das tut, was Sie wollen. Es gibt Ihnen eine Methode, die eine Zeit und einen Block benötigt und alles, was im Block passiert, verwendet die gefälschte Zeit.
pretend_now_is(2000,"jan",1,0) do
Time.now
end
Persönlich bevorzuge ich die Uhr injizierbare zu machen, etwa so:
def hello(clock=Time)
puts "the time is now: #{clock.now}"
end
Oder:
class MyClass
attr_writer :clock
def initialize
@clock = Time
end
def hello
puts "the time is now: #{@clock.now}"
end
end
jedoch viele bevorzugen eine spöttische/stubbing Bibliothek zu verwenden. In RSpec/flexmock können Sie:
Time.stub!(:now).and_return(Time.mktime(1970,1,1))
Oder in Mokka:
Time.stubs(:now).returns(Time.mktime(1970,1,1))
Der Testteil ist genau die Art von Antwort, die ich liefern würde. – nitecoder
Das wäre genau das, was ich auch getan hätte. Wenn Sie Ihren Code so schreiben, dass er leicht zu testen ist, müssen Sie keine obskuren Dinge tun, um ihn testbar zu machen. –
Während ich der generellen Idee zustimme, Zeug auf eine überprüfbarere Weise zu schreiben, gibt es Zeiten, in denen es einfach nicht praktikabel ist. Und Time.now ist eines dieser Beispiele. es kann in vielen Teilen des Systems verwendet werden und es die ganze Zeit herumzugeben wird zu viel Overhead sein. –
Ich mag die Timecop Bibliothek. Sie können Zeit Warps in Blockform (wie Zeit-Warp) tun:
Timecop.travel(6.days.ago) do
@model = TimeSensitiveMode.new
end
assert @model.times_up!
(Ja, können Sie nisten in Blockform eine Zeitreise.)
Sie auch Reise tun deklarative Zeit kann:
class MyTest < Test::Unit::TestCase
def setup
Timecop.travel(...)
end
def teardown
Timecop.return
end
end
Ich habe einige cucumber Helfer für Timecop here. Sie lassen Sie Dinge tun, wie:
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"
Sollte am Ende des letzten Tests ein Anführungszeichen stehen? –
Diese Helfer wurden in ein Juwel gelegt: https://github.com/zedtux/cucumber-timecop – approxiblue
Diese Art der Arbeiten und für die Verschachtelung erlaubt:
class Time
class << self
attr_accessor :stack, :depth
end
def self.warp(time)
Time.stack ||= []
Time.depth ||= -1
Time.depth += 1
Time.stack.push time
if Time.depth == 0
class << self
alias_method :real_now, :now
alias_method :real_new, :new
define_method :now do
stack[depth]
end
define_method :new do
now
end
end
end
yield
Time.depth -= 1
Time.stack.pop
class << self
if Time.depth < 0
alias_method :new, :real_new
alias_method :now, :real_now
remove_method :real_new
remove_method :real_now
end
end
end
end
Es leicht um undefing die Stapel und Tiefe Accessoren am Ende
Verbrauch verbessert werden könnte :
time1 = 2.days.ago
time2 = 5.months.ago
Time.warp(time1) do
Time.real_now.should_not == Time.now
Time.now.should == time1
Time.warp(time2) do
Time.now.should == time2
end
Time.now.should == time1
end
Time.now.should_not == time1
Time.now.should_not be_nil
Je nachdem, was Sie Time.now
zu vergleichen, manchmal yo Sie können Ihre Fixtures ändern, um das gleiche Ziel zu erreichen oder die gleiche Funktion zu testen. Zum Beispiel hatte ich eine Situation, in der ich eine Sache brauchte, wenn ein Datum in der Zukunft war und ein anderes, wenn es in der Vergangenheit war. Was konnte ich war tun, ist in meinen Vorrichtungen einig eingebetteten Rubin (erb):
future:
comparing_date: <%= Time.now + 10.years %>
...
past:
comparing_date: <%= Time.now - 10.years %>
...
Dann in Ihren Tests Sie dann wählen, welche zu verwenden, um die verschiedenen Funktionen oder Aktionen von der Zeit in Bezug auf Time.now
Basis zu testen .
Siehe auch this question, wo ich diesen Kommentar auch setzen.
Je nachdem, was Sie Time.now
vergleichen, können Sie manchmal Ihre Fixtures ändern, um das gleiche Ziel zu erreichen oder die gleiche Funktion zu testen.Zum Beispiel hatte ich eine Situation, in der ich eine Sache brauchte, wenn ein Datum in der Zukunft war und ein anderes, wenn es in der Vergangenheit war. Was konnte ich war tun, ist in meinen Vorrichtungen einig eingebetteten Rubin (erb):
future:
comparing_date: <%= Time.now + 10.years %>
...
past:
comparing_date: <%= Time.now - 10.years %>
...
Dann in Ihren Tests Sie dann wählen, welche zu verwenden, um die verschiedenen Funktionen oder Aktionen von der Zeit in Bezug auf Time.now
Basis zu testen .
Danke, ich fand das viel eleganter als das Fälschen von Time.now. Ihre Tests stellen auch sicher, dass es nirgends ein festes Datum gibt und Ihr Code funktioniert immer noch wie erwartet am Tag der Ausführung. – Benoit
Ich verwende RSpec und ich tat dies: Time.stub! (: Jetzt) .and_return (2.days.ago) bevor ich Time.now anrufe. Auf dieser Art und Weise die Zeit, die ich für diesen speziellen Testfall
Würden sich Ihre Tests eventuell nicht ändern? Haben Sie Beispiele? – Trip
für z.B. Wenn ich ein Mietsystem habe, möchte ich testen, ob das System Strafgebühren verlangt, wenn der Tag, an dem der Gegenstand zurückgegeben wird, verspätet ist. Ich muss Time.now manipulieren, damit der Artikel zurückkommt, wenn er zurückkommt. .. nicht sicher, ob Sie mich bekommen – Staelen
ich dies nur haben, das zur Kontrolle Ich bin in der Lage in meiner Test-Datei:
def time_right_now
current_time = Time.parse("07/09/10 14:20")
current_time = convert_time_to_utc(current_date)
return current_time
end
und in meiner Time_helper.rb Datei habe ich ein
def time_right_now
current_time= Time.new
return current_time
end
Also beim Testen wird die time_right_now überschrieben, um zu verwenden, was immer Sie wollen, es zu sein.
Ich extrahiere immer Time.now
in eine separate Methode, die ich im Schein in attr_accessor
verwandeln.
Vergessen Sie nicht, dass Time
lediglich eine Konstante ist, die sich auf ein Klassenobjekt bezieht. Wenn Sie bereit sind, eine Warnung zu verursachen, können Sie immer tun
real_time_class = Time
Time = FakeTimeClass
# run test
Time = real_time_class
Die kürzlich veröffentlichten Test::Redef
macht diese und anderen fakery einfach, auch ohne den Code in einer Abhängigkeitsinjektion Stil Umstrukturierung (besonders hilfreich, wenn Sie verwenden anderer Leute Code.)
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
jedoch andere Möglichkeiten vorsichtig sein, Zeit zu erhalten, dass dies nicht fälschen aus (Date.new
, eine kompilierte Erweiterung, die ihr eigenes System Anruf tätigt, Schnittstellen, um Dinge wie externe Datenbankserver, die den aktuellen Zeitstempel kennen ps, etc.) Es scheint, als ob die Timecop-Bibliothek diese Einschränkungen überwinden könnte.
Andere große Anwendungen schließen das Testen von Dingen wie "Was passiert, wenn ich versuche, diesen freundlichen HTTP-Client zu verwenden, aber es entscheidet, eine Ausnahme auszulösen, anstatt mir eine Zeichenfolge zurückzugeben?" ohne tatsächlich die Netzwerkbedingungen einzurichten, die zu dieser Ausnahme führen (was schwierig sein kann). Außerdem können Sie die Argumente für neu definierte Funktionen überprüfen.
hat das gleiche Problem, ich für eine Spezifikation für einen bestimmten Tag und Zeit nur zu fälschen Zeit gehabt hat, dass:
Time.stub!(:now).and_return(Time.mktime(2014,10,22,5,35,28))
das dir geben:
2014-10-22 05:35:28 -0700
was das Ausrufezeichen getan? Dies ist mit Mokka-Edelstein? –
eigentlich denke ich 'stub!' Ist entzogen und Sie können einfach 'stub' jetzt verwenden –
Mit Rspec 3.2, wenn die einzige einfache Art und Weise zu fälschen Time.now Rückgabewert gefunden ist:
now = Time.parse("1969-07-20 20:17:40")
allow(Time).to receive(:now) { now }
Jetzt Time.now wird immer wieder zurückkehrt das Datum der Apol lo 11 Landung auf dem Mond.
Wenn Sie Active haben eingeschlossen, könnten Sie http://api.rubyonrails.org/classes/ActiveSupport/Testing/TimeHelpers.html
- 1. Wie man ndb.get_context() vortäuscht.
- 2. Wie man Standort iOS vortäuscht
- 3. Wie man private Getters vortäuscht?
- 4. Wie man HttpApplication/HttpContext zum Testen vortäuscht oder vortäuscht
- 5. Wie man Endfeld vortäuscht? Mockito/PowerMock
- 6. Wie man Kontext mit Mockito vortäuscht?
- 7. Wie man Erweiterungsmethoden mit Rhino Mock vortäuscht?
- 8. Wie man AJAX-Anruf mit NSURLProtocol vortäuscht?
- 9. Wie man Datei in Javascript vortäuscht?
- 10. python wie man eine Methode vortäuscht?
- 11. Wie man eine Veranstaltung in mootools vortäuscht?
- 12. Wie man eine BulkWriteException in Python vortäuscht?
- 13. Wie man nur eine Methode vortäuscht?
- 14. Wie man Vorlagen mit Google Mock vortäuscht?
- 15. Wie man ISerializable-Klassen mit Moq vortäuscht?
- 16. Wie man Thread.sleep() mit PowerMock vortäuscht?
- 17. Angular $ httpBackend wie man eine Fehlerreaktion vortäuscht?
- 18. Wie man statische Methoden in Kotlin vortäuscht?
- 19. Keeping Time.now accuarate
- 20. Stubbing Time.now mit RSpec
- 21. Wie man eine Methode mit funktionalen Argumenten in Scala vortäuscht?
- 22. Wie man Inputstream vortäuscht, um Eigenschaften in Java zu laden
- 23. Wie man eine einzelne Methode in Java vortäuscht
- 24. Wie man Djangos jetzt Funktion in allen Anwendungsfunktionen vortäuscht
- 25. Wie man statische Methode vortäuscht, die letzte Klasse zurückgibt?
- 26. Wie man os.walk in Python mit einem temporären Dateisystem vortäuscht?
- 27. Reaktionstest; wie man componentDidMount vortäuscht oder es überschreibt?
- 28. React js - Wie man Kontext vortäuscht beim Testen der Komponente
- 29. Wie man unidirektionale Bindungsparameter mit $ Controller Dekorator vortäuscht?
- 30. Wie man geschützte virtuelle Mitglieder mit Rhino.Mocks vortäuscht?
Gibt es ein Timelord Ruby Gem? : P – Rob
Schließen! Da ist Timecop. (Siehe meine Antwort unten.) –