Neu in .NET 8.0 [17]: Zeitabstraktion für Tests mit Zeitangaben

In .NET 8.0 existiert mit der abstrakten Klasse TimeProvider ein einfacher Weg, Zeitangaben inklusive Zeitzone beliebig im Rahmen von Tests vorzutäuschen.

In Pocket speichern vorlesen Druckansicht
Frau dreht an der Uhr

(Bild: New Africa/Shutterstock.com)

Lesezeit: 1 Min.
Von
  • Dr. Holger Schwichtenberg

In der Basisklassenbibliothek hat Microsoft .NET 8.0 mit der abstrakten Klasse TimeProvider eine einfache Möglichkeit ergänzt, Zeitangaben inklusive Zeitzone beliebig im Rahmen von Tests vorzutäuschen.

Der Dotnet-Doktor – Holger Schwichtenberg

Dr. Holger Schwichtenberg ist technischer Leiter des Expertennetzwerks www.IT-Visions.de, das mit 53 renommierten Experten zahlreiche mittlere und große Unternehmen durch Beratungen und Schulungen sowie bei der Softwareentwicklung unterstützt. Durch seine Auftritte auf zahlreichen nationalen und internationalen Fachkonferenzen sowie mehr als 90 Fachbücher und mehr als 1500 Fachartikel gehört Holger Schwichtenberg zu den bekanntesten Experten für .NET und Webtechniken in Deutschland.

Eine Abstraktion für die aktuelle Zeit anstelle der Nutzung von System.DateTime.Now, System.DateTime.UtcNow und System.DateTimeOffset.Now haben schon viele Entwicklerinnen und Entwickler geschrieben, denn echte Unit Tests für Programmcode, der von der Zeit oder dem Datum abhängig ist, braucht eine Abstraktion. Ansonsten müsste man bis zu einer bestimmten Uhrzeit oder einem Datum warten, um die Tests zu starten.

Microsoft liefert in .NET 8.0 nun eine eingebaute Abstraktion. Auch die Zeitangaben in Task.Delay() und Task.Async() können darauf zurückgreifen.

Das folgende Listing zeigt mehrere Aspekte:

  • TimeProvider.System liefert einen TimeProvider mit der realen Zeit laut Systemuhr.
  • FakeTimeProvider ist eine Klasse von Microsoft, die im NuGet-Paket Microsoft.Extensions.TimeProvider.Testing geliefert wird. Diese Klasse erlaubt eine feste Zeitvorgabe, die man manuell mit Advance() unter Angabe eines TimeSpan-Objekts oder bei jedem Auslesen vorstellen kann, beispielsweise fakeTime.AutoAdvanceAmount = TimeSpan.FromHours(1).
class FCL_TimeProvider
{
 
 public async Task Run()
 {
  void PrintTime(TimeProvider timeProvider)
  {
   Console.Write("Lokale Zeit: " + timeProvider.GetLocalNow());
   Console.WriteLine(" | UTC: " + timeProvider.GetUtcNow());
  }
 
  void Callback(TimeProvider timeProvider)
  {
   Console.WriteLine("Time mit " + timeProvider.GetType());
   PrintTime(timeProvider);
  }
 
  CUI.H2("Reguläre Systemzeit");
  PrintTime(TimeProvider.System);
 
  // https://www.nuget.org/packages/\
  // Microsoft.Extensions.TimeProvider.Testing/
  CUI.H2("Vorgetäuschte Zeit Time-Provider aus “+
         “Microsoft.Extensions.TimeProvider.Testing"); 
  var fakeTime = new 
    FakeTimeProvider(new(DateTime.Parse("14.11.2023 18:00:00")));
  PrintTime(fakeTime); // 14.11.2023 18 Uhr
  Console.WriteLine("Wir stellen die Zeit nun 30 Minuten vor");
  fakeTime.Advance(TimeSpan.FromMinutes(30));
  // 14.11.2023 18:30 Uhr:
  Console.WriteLine("UTC: " + fakeTime.GetUtcNow()); 
  Console.WriteLine("Wir stellen die Zeit bei jedem Lesen " + 
                    "der Zeit 1 Stunde vor");
  fakeTime.AutoAdvanceAmount = TimeSpan.FromHours(1);
  // 14.11.2023 19:30 Uhr: 
  Console.WriteLine("UTC: " + fakeTime.GetUtcNow()); 
  // 14.11.2023 20:30 Uhr:
  Console.WriteLine("UTC: " + fakeTime.GetUtcNow()); 
  // 14.11.2023 21:30 Uhr: 
  Console.WriteLine("UTC: " + fakeTime.GetUtcNow()); 
 
  async Task Wait5Seconds(TimeProvider t)
  {
   CUI.Cyan("Warten beginnt");
   PrintTime(TimeProvider.System);
   await t.Delay(new TimeSpan(0, 0, 6));
   // oder
   //await Task.Delay(new TimeSpan(0, 0, 5), fakeTimeProvider);
   PrintTime(TimeProvider.System);
   CUI.Cyan("Warten beendet!");
  }
 
  CUI.H2("6 Sekunden warten auf TimeProvider.System");
  await Wait5Seconds(TimeProvider.System);
  CUI.H2("6 Sekunden warten auf FakeTimeProvider von Microsoft");
  var ErhoeheZeitNachEinerSekundeUm10Sekunden = async () =>
  {
   await Task.Delay(new TimeSpan(0, 0, 1));
   fakeTime.Advance(TimeSpan.FromSeconds(10));
  };
#pragma warning disable CS4014 
  ErhoeheZeitNachEinerSekundeUm10Sekunden();
#pragma warning restore CS4014 
  //--> das endet nie, wenn man Advance() nicht aufruft!:
  await Wait5Seconds(fakeTime); 
 }
}
Online-Konferenz zu .NET 9.0 am 19. November

In der Online-Konferenz betterCode() .NET 9.0 am 19. November 2024 von iX und dpunkt.verlag werden .NET-Experten von www.IT-Visions.de den fertigen Stand von .NET 9.0 anhand von Praxisbeispielen präsentieren. Dazu zählen die Neuerungen bezüglich des .NET 9.0 SDK, C# 13.0, ASP.NET Core 9.0, Blazor 9.0, OR-Mapping mit Entity Framework Core 9.0, Windows Forms 9.0, WPF 9.0, WinUI, Cross-Plattform-Entwicklung mit .NET MAUI 9.0 und ein Ausblick auf .NET 10.0.

Der Ticketverkauf ist bereits gestartet: Vor Bekanntgabe des Programms sind vergünstigte Blind-Bird-Tickets erhältlich.

(rme)