Dass das Testen unseres Codes ein entscheidender und wesentlicher Bestandteil des Lebenszyklus für die Lebensweise der Softwareentwicklung ist. Dies ist vielleicht noch wichtiger, wenn wir über KI- und ML -Systeme diskutieren, bei denen eine inhärente Unsicherheit und ein halluzinatorisches Ingredient von Anfang an bereits eingebacken werden.
In diesem allgemeinen Testframework kann der Testcode, der sich je nach aktuellem Datum oder Uhrzeit unterschiedlich verhält, ein realer Kopfschmerz sein. Wie überprüfen Sie die Logik zuverlässig, die nur um Mitternacht auslöst, relative Daten („vor 2 Stunden“) berechnet oder knifflige Situationen wie Schaltjahre oder Monatsends behandelt? Das manuelle Verspotten von Pythons DateTime-Modul kann umständlich und fehleranfällig sein.
Wenn Sie jemals damit gerungen haben, sind Sie nicht allein. Aber was wäre, wenn Sie einfach … die Zeit anhalten könnten? Oder sogar in Ihren Exams durchlaufen?
Genau das ermöglicht die Freezegun -Bibliothek Sie. Es ist eine elegante Lösung für ein gemeinsames Testproblem, aber viele erfahrene Python -Entwickler haben noch nie davon gehört.
Freezegun Ermöglicht es Ihren Python -Exams, bestimmte Momente in der Zeit zu simulieren, indem Sie die Module für DateTime, Datum, Uhrzeit und Pendelspython verspotten. Es ist einfach zu bedienen, aber leistungsfähig, um deterministische und zuverlässige Exams für zeitempfindlichen Code zu erstellen.
Warum ist Freezegun so hilfreich?
- Determinismus. Dies ist der Hauptvorteil von Freezegun. Exams mit Zeit werden völlig vorhersehbar. Ausführen von DateTime.Now () In einem gefrorenen Block gibt den gleichen gefrorenen Zeitstempel zurück, wodurch die durch Millisekundenunterschiede oder Datumsüberschreitungen während der Testausführung verursachten Exams beseitigt werden.
- Einfachheit. Im Vergleich zum manuelles Patchen datetime.now oder verwenden unittest.mockFreezegun ist oft viel sauberer und benötigt weniger Boilerplate -Code, insbesondere wenn die Zeit vorübergehend geändert wird.
- Zeitreisen. Simuliert einfach bestimmte Daten und Zeiten – Vergangenheit, Gegenwart oder Zukunft. Dies ist entscheidend für das Testen von Randfällen, wie z. B. die Verarbeitung von Jahresende, Sekunden, Sekunden, Tageslichtsparenübergänge oder lediglich an bestimmte Ereignisse gebundene Logik.
- Relative Zeitprüfung. Testerfunktionen, die die relativen Zeiten berechnen (z. B. „in 3 Tagen“), indem die Zeit gefriert und Zeitstempel im Verhältnis zu diesem gefrorenen Second erstellt werden.
- Ticken Sie tock. Freezegun ermöglicht die Zeit zum Vormarsch („Tick“) aus dem gefrorenen Second innerhalb eines Exams, der perfekt zum Testen von Zeitüberschreitungen, Dauern oder Sequenzen zeitabhängiger Ereignisse geeignet ist.
Hoffentlich habe ich Sie davon überzeugt, dass Freezegun eine wertvolle Ergänzung Ihrer Python -Toolbox sein könnte. Lassen Sie es uns in Aktion sehen, indem wir einige Beispielcode -Snippets durchsehen.
Einrichten einer Entwicklerumgebung
Lassen Sie uns vorher jedoch eine Entwicklungsumgebung einrichten, mit der wir experimentieren können. Ich benutze dafür Miniconda, aber Sie können jedes Device verwenden, mit dem Sie vertraut sind.
Ich bin ein Home windows -Benutzer, aber ich entwickle oft mit WSL2 Ubuntu für Home windows, was ich hier tun werde.
Der gesamte Code, den ich zeige, sollte unter Home windows oder Unix-ähnlichen Betriebssystemen gleich intestine funktionieren.
# Create and activate a brand new dev surroundings
#
(base) $ conda create -n freezegun python=3.12 -y
(base) $ conda activate freezegun
Jetzt können wir die verbleibenden notwendigen Bibliotheken installieren.
(freezegun) $ pip set up freezegun jupyter
Ich werde Jupyter Pocket book verwenden, um meinen Code auszuführen. Geben Sie mit jupyter pocket book in Ihre Eingabeaufforderung. Sie sollten ein Jupyter -Notizbuch in Ihrem Browser geöffnet sehen. Wenn das nicht automatisch passiert, werden Sie wahrscheinlich eine Bildschirminformationen nach dem feststellen jupyter pocket book Befehl. Nahe unten finden Sie eine URL zum Kopieren und Einfügen in Ihren Browser, um das Jupyter -Notizbuch zu starten.
Ihre URL wird anders sein als meine, aber sie sollte ungefähr so aussehen:-
http://127.0.0.1:8888/tree?token=3b9f7bd07b6966b41b68e2350721b2d0b6f388d248cc69da
Abgesehen von: Der Code, den ich in meinen folgenden Beispielen zeige, nutzt die Python stark behaupten Befehl. Wenn Sie diese Funktion zuvor noch nicht begegnet sind oder in Python nicht viel Unit -Exams durchgeführt haben, wird Assert verwendet, um zu testen, ob eine Bedingung wahr ist, und wenn dies nicht der Fall ist, erhöht sie eine
AssertionError.Dies hilft bei der Entwicklung von Themen und wird häufig zum Debugieren und Validieren von Annahmen im Code verwendet.
Beispiel 1: Primary Time Erezing mit einem Dekorateur
Die häufigste Artwork, Freezegun zu verwenden, ist über seinen DekorateurAnwesend @Freeze_time, Das ermöglicht es Ihnen „Setzen Sie“ eine bestimmte Tageszeit, um verschiedene zeitbezogene Funktionen zu testen.
import datetime
from freezegun import freeze_time
def get_greeting():
now = datetime.datetime.now()
print(f" Inside get_greeting(), now = {now}") # Added print
if now.hour < 12:
return "Good morning!"
elif 12 <= now.hour < 18:
return "Good afternoon!"
else:
return "Good night!"
# Take a look at the morning greeting
@freeze_time("2023-10-27 09:00:00")
def test_morning_greeting():
print("Operating test_morning_greeting:")
greeting = get_greeting()
print(f" -> Obtained greeting: '{greeting}'")
assert greeting == "Good morning!"
# Take a look at the night greeting
@freeze_time("2023-10-27 21:30:00")
def test_evening_greeting():
print("nRunning test_evening_greeting:")
greeting = get_greeting()
print(f" -> Obtained greeting: '{greeting}'")
assert greeting == "Good night!"
# Run the checks
test_morning_greeting()
test_evening_greeting()
print("nBasic decorator checks handed!")
# --- Failure State of affairs ---
# What occurs if we do not freeze time?
print("n--- Operating with out freeze_time (may fail relying on precise time) ---")
def test_morning_greeting_unfrozen():
print("Operating test_morning_greeting_unfrozen:")
greeting = get_greeting()
print(f" -> Obtained greeting: '{greeting}'")
# This assertion is now unreliable! It will depend on once you run the code.
attempt:
assert greeting == "Good morning!"
print(" (Handed by probability)")
besides AssertionError:
print(" (Failed as anticipated - time wasn't 9 AM)")
test_morning_greeting_unfrozen()
Und die Ausgabe.
Operating test_morning_greeting:
Inside get_greeting(), now = 2023-10-27 09:00:00
-> Obtained greeting: 'Good morning!'
Operating test_evening_greeting:
Inside get_greeting(), now = 2023-10-27 21:30:00
-> Obtained greeting: 'Good night!'
Primary decorator checks handed!
--- Operating with out freeze_time (may fail relying on precise time) ---
Operating test_morning_greeting_unfrozen:
Inside get_greeting(), now = 2025-04-16 15:00:37.363367
-> Obtained greeting: 'Good afternoon!'
(Failed as anticipated - time wasn't 9 AM)
Beispiel 2: Primary Time Evezing mit einem Kontextmanager
Erstellen Sie einen „Block“ der gefrorenen Zeit.
import datetime
from freezegun import freeze_time
def process_batch_job():
start_time = datetime.datetime.now()
# Simulate work
end_time = datetime.datetime.now() # In actuality, time would cross
print(f" Inside job: Begin={start_time}, Finish={end_time}") # Added print
return (start_time, end_time)
def test_job_timestamps_within_frozen_block():
print("nRunning test_job_timestamps_within_frozen_block:")
frozen_time_str = "2023-11-15 10:00:00"
with freeze_time(frozen_time_str):
print(f" Getting into frozen block at {frozen_time_str}")
begin, finish = process_batch_job()
print(f" Asserting begin == finish: {begin} == {finish}")
assert begin == finish
print(f" Asserting begin == frozen time: {begin} == {datetime.datetime(2023, 11, 15, 10, 0, 0)}")
assert begin == datetime.datetime(2023, 11, 15, 10, 0, 0)
print(" Assertions inside block handed.")
print(" Exited frozen block.")
now_outside = datetime.datetime.now()
print(f" Time exterior block: {now_outside} (needs to be actual time)")
# This assertion simply exhibits time is unfrozen, worth will depend on actual time
assert now_outside != datetime.datetime(2023, 11, 15, 10, 0, 0)
test_job_timestamps_within_frozen_block()
print("nContext supervisor check handed!")
Die Ausgabe.
Operating test_job_timestamps_within_frozen_block:
Getting into frozen block at 2023-11-15 10:00:00
Inside job: Begin=2023-11-15 10:00:00, Finish=2023-11-15 10:00:00
Asserting begin == finish: 2023-11-15 10:00:00 == 2023-11-15 10:00:00
Asserting begin == frozen time: 2023-11-15 10:00:00 == 2023-11-15 10:00:00
Assertions inside block handed.
Exited frozen block.
Time exterior block: 2025-04-16 15:10:15.231632 (needs to be actual time)
Context supervisor check handed!
Beispiel 3: Die Zeit mit Tick vorantreiben
Simulieren Sie die Zeit innerhalb eines gefrorenen Zeitraums.
import datetime
import time
from freezegun import freeze_time
def check_if_event_expired(event_timestamp, expiry_duration_seconds):
now = datetime.datetime.now()
expired = now > event_timestamp + datetime.timedelta(seconds=expiry_duration_seconds)
print(f" Checking expiry: Now={now}, Occasion={event_timestamp}, ExpiresAt={event_timestamp + datetime.timedelta(seconds=expiry_duration_seconds)} -> Expired={expired}")
return expired
# --- Guide ticking utilizing context supervisor ---
def test_event_expiry_manual_tick():
print("nRunning test_event_expiry_manual_tick:")
with freeze_time("2023-10-27 12:00:00") as freezer:
event_time_in_freeze = datetime.datetime.now()
expiry_duration = 60
print(f" Occasion created at: {event_time_in_freeze}")
print(" Checking instantly after creation:")
assert not check_if_event_expired(event_time_in_freeze, expiry_duration)
# Advance time by 61 seconds
delta_to_tick = datetime.timedelta(seconds=61)
print(f" Ticking ahead by {delta_to_tick}...")
freezer.tick(delta=delta_to_tick)
print(f" Time after ticking: {datetime.datetime.now()}")
print(" Checking after ticking:")
assert check_if_event_expired(event_time_in_freeze, expiry_duration)
print(" Guide tick check completed.")
# --- Failure State of affairs ---
@freeze_time("2023-10-27 12:00:00") # No tick=True or guide tick
def test_event_expiry_fail_without_tick():
print("n--- Operating test_event_expiry_fail_without_tick (EXPECT ASSERTION ERROR) ---")
event_time = datetime.datetime.now()
expiry_duration = 60
print(f" Occasion created at: {event_time}")
# Simulate work or ready - with out tick, time would not advance!
time.sleep(0.1)
print(f" Time after simulated wait: {datetime.datetime.now()}")
print(" Checking expiry (incorrectly, time did not transfer):")
attempt:
# This could ideally be True, however will probably be False with out ticking
assert check_if_event_expired(event_time, expiry_duration)
besides AssertionError:
print(" AssertionError: Occasion didn't expire, as anticipated with out tick.")
print(" Failure situation completed.")
# Run each checks
test_event_expiry_manual_tick()
test_event_expiry_fail_without_tick()
Dies gibt Folgendes aus.
Operating test_event_expiry_manual_tick:
Occasion created at: 2023-10-27 12:00:00
Checking instantly after creation:
Checking expiry: Now=2023-10-27 12:00:00, Occasion=2023-10-27 12:00:00, ExpiresAt=2023-10-27 12:01:00 -> Expired=False
Ticking ahead by 0:01:01...
Time after ticking: 2023-10-27 12:01:01
Checking after ticking:
Checking expiry: Now=2023-10-27 12:01:01, Occasion=2023-10-27 12:00:00, ExpiresAt=2023-10-27 12:01:00 -> Expired=True
Guide tick check completed.
--- Operating test_event_expiry_fail_without_tick (EXPECT ASSERTION ERROR) ---
Occasion created at: 2023-10-27 12:00:00
Time after simulated wait: 2023-10-27 12:00:00
Checking expiry (incorrectly, time did not transfer):
Checking expiry: Now=2023-10-27 12:00:00, Occasion=2023-10-27 12:00:00, ExpiresAt=2023-10-27 12:01:00 -> Expired=False
AssertionError: Occasion didn't expire, as anticipated with out tick.
Failure situation completed.
Beispiel 4: Testen der relativen Daten
Freezegun sorgt für eine stabile „Zeit“ -Logik.
import datetime
from freezegun import freeze_time
def format_relative_time(timestamp):
now = datetime.datetime.now()
delta = now - timestamp
rel_time_str = ""
if delta.days > 0:
rel_time_str = f"{delta.days} days in the past"
elif delta.seconds >= 3600:
hours = delta.seconds // 3600
rel_time_str = f"{hours} hours in the past"
elif delta.seconds >= 60:
minutes = delta.seconds // 60
rel_time_str = f"{minutes} minutes in the past"
else:
rel_time_str = "simply now"
print(f" Formatting relative time: Now={now}, Timestamp={timestamp} -> '{rel_time_str}'")
return rel_time_str
@freeze_time("2023-10-27 15:00:00")
def test_relative_time_formatting():
print("nRunning test_relative_time_formatting:")
# Occasion occurred 2 days and three hours in the past relative to frozen time
past_event = datetime.datetime(2023, 10, 25, 12, 0, 0)
assert format_relative_time(past_event) == "2 days in the past"
# Occasion occurred 45 minutes in the past
recent_event = datetime.datetime.now() - datetime.timedelta(minutes=45)
assert format_relative_time(recent_event) == "45 minutes in the past"
# Occasion occurred simply now
current_event = datetime.datetime.now() - datetime.timedelta(seconds=10)
assert format_relative_time(current_event) == "simply now"
print(" Relative time checks handed!")
test_relative_time_formatting()
# --- Failure State of affairs ---
print("n--- Operating relative time with out freeze_time (EXPECT FAILURE) ---")
def test_relative_time_unfrozen():
# Use the identical previous occasion timestamp
past_event = datetime.datetime(2023, 10, 25, 12, 0, 0)
print(f" Testing with past_event = {past_event}")
# It will examine towards the *precise* present time, not Oct twenty seventh, 2023
formatted_time = format_relative_time(past_event)
attempt:
assert formatted_time == "2 days in the past"
besides AssertionError:
# The precise distinction will probably be a lot bigger!
print(f" AssertionError: Anticipated '2 days in the past', however obtained '{formatted_time}'. Failed as anticipated.")
test_relative_time_unfrozen()
Die Ausgabe.
Operating test_relative_time_formatting:
Formatting relative time: Now=2023-10-27 15:00:00, Timestamp=2023-10-25 12:00:00 -> '2 days in the past'
Formatting relative time: Now=2023-10-27 15:00:00, Timestamp=2023-10-27 14:15:00 -> '45 minutes in the past'
Formatting relative time: Now=2023-10-27 15:00:00, Timestamp=2023-10-27 14:59:50 -> 'simply now'
Relative time checks handed!
--- Operating relative time with out freeze_time (EXPECT FAILURE) ---
Testing with past_event = 2023-10-25 12:00:00
Formatting relative time: Now=2023-10-27 12:00:00, Timestamp=2023-10-25 12:00:00 -> '2 days in the past'
Beispiel 5: Umgang mit bestimmten Daten (Ende des Monats)
Testkantenfälle wie Schaltjahre zuverlässig.
import datetime
from freezegun import freeze_time
def is_last_day_of_month(check_date):
next_day = check_date + datetime.timedelta(days=1)
is_last = next_day.month != check_date.month
print(f" Checking if {check_date} is final day of month: Subsequent day={next_day}, IsLast={is_last}")
return is_last
print("nRunning particular date logic checks:")
@freeze_time("2023-02-28") # Non-leap 12 months
def test_end_of_february_non_leap():
as we speak = datetime.date.as we speak()
assert is_last_day_of_month(as we speak) is True
@freeze_time("2024-02-28") # Bissextile year
def test_end_of_february_leap_not_yet():
as we speak = datetime.date.as we speak()
assert is_last_day_of_month(as we speak) is False # Feb twenty ninth exists
@freeze_time("2024-02-29") # Bissextile year - final day
def test_end_of_february_leap_actual():
as we speak = datetime.date.as we speak()
assert is_last_day_of_month(as we speak) is True
@freeze_time("2023-12-31")
def test_end_of_year():
as we speak = datetime.date.as we speak()
assert is_last_day_of_month(as we speak) is True
test_end_of_february_non_leap()
test_end_of_february_leap_not_yet()
test_end_of_february_leap_actual()
test_end_of_year()
print("Particular date logic checks handed!")
#
# Output
#
Operating particular date logic checks:
Checking if 2023-02-28 is final day of month: Subsequent day=2023-03-01, IsLast=True
Checking if 2024-02-28 is final day of month: Subsequent day=2024-02-29, IsLast=False
Checking if 2024-02-29 is final day of month: Subsequent day=2024-03-01, IsLast=True
Checking if 2023-12-31 is final day of month: Subsequent day=2024-01-01, IsLast=True
pecific date logic checks handed!
Beispiel 6: Zeitzonen
Testen Sie Zeitzone-bewusstes Code korrekt und bearbeiten Sie Offsets und Übergänge wie BST/GMT.
# Requires Python 3.9+ for zoneinfo or `pip set up pytz` for older variations
import datetime
from freezegun import freeze_time
attempt:
from zoneinfo import ZoneInfo # Python 3.9+
besides ImportError:
from pytz import timezone as ZoneInfo # Fallback for older Python/pytz
def get_local_and_utc_time():
# Assume native timezone is Europe/London for this instance
local_tz = ZoneInfo("Europe/London")
now_utc = datetime.datetime.now(datetime.timezone.utc)
now_local = now_utc.astimezone(local_tz)
print(f" Getting instances: UTC={now_utc}, Native={now_local} ({now_local.tzname()})")
return now_local, now_utc
# Freeze time as 9 AM UTC. London is UTC+1 in summer time (BST). Oct 27 is BST.
@freeze_time("2023-10-27 09:00:00", tz_offset=0) # tz_offset=0 means the frozen time string IS UTC
def test_time_in_london_bst():
print("nRunning test_time_in_london_bst:")
local_time, utc_time = get_local_and_utc_time()
assert utc_time.hour == 9
assert local_time.hour == 10 # London is UTC+1 on this date
assert local_time.tzname() == "BST"
# Freeze time as 9 AM UTC. Use December twenty seventh, which is GMT (UTC+0)
@freeze_time("2023-12-27 09:00:00", tz_offset=0)
def test_time_in_london_gmt():
print("nRunning test_time_in_london_gmt:")
local_time, utc_time = get_local_and_utc_time()
assert utc_time.hour == 9
assert local_time.hour == 9 # London is UTC+0 on this date
assert local_time.tzname() == "GMT"
test_time_in_london_bst()
test_time_in_london_gmt()
print("nTimezone checks handed!")
#
# Output
#
Operating test_time_in_london_bst:
Getting instances: UTC=2023-10-27 09:00:00+00:00, Native=2023-10-27 10:00:00+01:00 (BST)
Operating test_time_in_london_gmt:
Getting instances: UTC=2023-12-27 09:00:00+00:00, Native=2023-12-27 09:00:00+00:00 (GMT)
Timezone checks handed!
Beispiel 7: Explizite Zeitreisen mit der Funktion move_to
Springen Sie zwischen spezifischen Zeitpunkten in einem einzelnen Take a look at für komplexe zeitliche Sequenzen.
import datetime
from freezegun import freeze_time
class ReportGenerator:
def __init__(self):
self.creation_time = datetime.datetime.now()
self.knowledge = {"standing": "pending", "generated_at": None}
print(f" Report created at {self.creation_time}")
def generate(self):
self.knowledge("standing") = "generated"
self.knowledge("generated_at") = datetime.datetime.now()
print(f" Report generated at {self.knowledge('generated_at')}")
def get_status_update(self):
now = datetime.datetime.now()
if self.knowledge("standing") == "generated":
time_since_generation = now - self.knowledge("generated_at")
standing = f"Generated {time_since_generation.seconds} seconds in the past."
else:
time_since_creation = now - self.creation_time
standing = f"Pending for {time_since_creation.seconds} seconds."
print(f" Standing replace at {now}: '{standing}'")
return standing
def test_report_lifecycle():
print("nRunning test_report_lifecycle:")
with freeze_time("2023-11-01 10:00:00") as freezer:
report = ReportGenerator()
assert report.knowledge("standing") == "pending"
# Verify standing after 5 seconds
target_time = datetime.datetime(2023, 11, 1, 10, 0, 5)
print(f" Transferring time to {target_time}")
freezer.move_to(target_time)
assert report.get_status_update() == "Pending for five seconds."
# Generate the report at 10:01:00
target_time = datetime.datetime(2023, 11, 1, 10, 1, 0)
print(f" Transferring time to {target_time} and producing report")
freezer.move_to(target_time)
report.generate()
assert report.knowledge("standing") == "generated"
assert report.get_status_update() == "Generated 0 seconds in the past."
# Verify standing 30 seconds after technology
target_time = datetime.datetime(2023, 11, 1, 10, 1, 30)
print(f" Transferring time to {target_time}")
freezer.move_to(target_time)
assert report.get_status_update() == "Generated 30 seconds in the past."
print(" Complicated lifecycle check handed!")
test_report_lifecycle()
# --- Failure State of affairs ---
def test_report_lifecycle_fail_forgot_move():
print("n--- Operating lifecycle check (FAIL - forgot move_to) ---")
with freeze_time("2023-11-01 10:00:00") as freezer:
report = ReportGenerator()
assert report.knowledge("standing") == "pending"
# We INTEND to test standing after 5 seconds, however FORGET to maneuver time
print(f" Checking standing (time continues to be {datetime.datetime.now()})")
# freezer.move_to("2023-11-01 10:00:05") # <-- Forgotten!
attempt:
assert report.get_status_update() == "Pending for five seconds."
besides AssertionError as e:
print(f" AssertionError: {e}. Failed as anticipated.")
test_report_lifecycle_fail_forgot_move()
Hier ist die Ausgabe.
Operating test_report_lifecycle:
Report created at 2023-11-01 10:00:00
Transferring time to 2023-11-01 10:00:05
Standing replace at 2023-11-01 10:00:05: 'Pending for five seconds.'
Transferring time to 2023-11-01 10:01:00 and producing report
Report generated at 2023-11-01 10:01:00
Standing replace at 2023-11-01 10:01:00: 'Generated 0 seconds in the past.'
Transferring time to 2023-11-01 10:01:30
Standing replace at 2023-11-01 10:01:30: 'Generated 30 seconds in the past.'
Complicated lifecycle check handed!
--- Operating lifecycle check (FAIL - forgot move_to) ---
Report created at 2023-11-01 10:00:00
Checking standing (time continues to be 2023-11-01 10:00:00)
Standing replace at 2023-11-01 10:00:00: 'Pending for 0 seconds.'
AssertionError: . Failed as anticipated.
Zusammenfassung
Freezegun ist ein fantastisches Device für jeden Python -Entwickler, der Code mit Daten und Zeiten testen muss. Es verwandelt potenziell schuppige, schwer zu schriftliche Exams in einfache, robuste und deterministische. Indem Sie mit Leichtigkeit einfrieren, ankreuzen und durch die Zeit reisen können – und es klar machen, wenn die Zeit ist nicht kontrolliert – Es entsperren die Fähigkeit, bisherige herausfordernde Szenarien effektiv und zuverlässig zu testen.
Um dies zu veranschaulichen, lieferte ich mehrere Beispiele für verschiedene Fälle, die Datums- und Zeittests umfassten, und zeigte, wie die Verwendung von Freezegun viele der Hindernisse beseitigt, auf die ein herkömmlicher Take a look at -Framework begegnen könnte.
Während wir die Kernfunktionalitäten behandelt haben, können Sie mehr mit Freezegun tun, und ich empfehle, sich zu überprüfen Github -Seite.
Kurz gesagt, Freezegun ist eine Bibliothek, die Sie kennen und verwenden sollten, wenn Ihr Code mit der Zeit handelt und Sie sie gründlich und zuverlässig testen müssen.
