TimeScheduler 0.1.1-preview

Suggested Alternatives

TimeProviderExtensions

This is a prerelease version of TimeScheduler.
There is a newer version of this package available.
See the version list below for details.
dotnet add package TimeScheduler --version 0.1.1-preview                
NuGet\Install-Package TimeScheduler -Version 0.1.1-preview                
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="TimeScheduler" Version="0.1.1-preview" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add TimeScheduler --version 0.1.1-preview                
#r "nuget: TimeScheduler, 0.1.1-preview"                
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install TimeScheduler as a Cake Addin
#addin nuget:?package=TimeScheduler&version=0.1.1-preview&prerelease

// Install TimeScheduler as a Cake Tool
#tool nuget:?package=TimeScheduler&version=0.1.1-preview&prerelease                

Time Scheduler

A library that wraps common .NET scheduling and time related operations in an abstraction, that enables controlling time during testing.

Installation

Get the latest release from https://www.nuget.org/packages/TimeScheduler

Control time during tests

If a system under test (SUT) uses things like Task.Delay, DateTimeOffset.UtcNow, or PeriodicTimer, it becomes hard to create tests that runs fast and predictably.

The idea is to replace the use of e.g. Task.Delay with an abstraction, the ITimeScheduler, that in production is represented by the DefaultScheduler, that just uses the real Task.Delay. During testing it is now possible to pass in TestScheduler, that allows the test to control the progress of time, making it possible to skip ahead, e.g. 10 minutes, and also pause time, leading to fast and predictable tests.

As an example, lets test the StuffService below that performs a specific tasks every 10 second:

public class StuffService 
{
  private static readonly TimeSpan doStuffDelay = TimeSpan.FromSeconds(10);
  private readonly ITimeScheduler scheduler;
  private readonly List<string> container;

  public StuffService(ITimeScheduler scheduler, List<string> container)
  {
    this.scheduler = scheduler;
    this.container = container;
  }
  
  public async Task DoStuff(CancellationToken cancelllationToken)
  {
    using var periodicTimer = scheduler.PeriodicTimer(doStuffDelay);
    
    while (await periodicTimer.WaitForNextTickAsync(cancellationToken))
    {
      container.Add("stuff");    
    }
  }
}

The test, using xUnit and FluentAssertions, could look like this:

[Fact]
public void DoStuff_does_stuff_every_10_seconds()
{
  // Arrange
  var scheduler = new TestScheduler();
  var container = new List<string>();  
  var sut = new StuffService(scheduler, container);
  
  // Act
  _ = sut.DoStuff(CancellationToken.None);
  scheduler.ForwardTime(TimeSpan.FromSeconds(10));
  
  // Assert
  container.Should().ContainSingle();
}

Set up in production

To use in production, pass in DefaultScheduler to the types that depend on ITimeScheduler. This can be done directly, or via an IoC Container, e.g. .NETs built-in IServiceCollection like so:

services.AddSingleton<ITimeScheduler, DefaultScheduler>();
Product Compatible and additional computed target framework versions.
.NET net6.0 is compatible.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net6.0

    • No dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.