SweetMock.Extensions.TimeProvider 0.9.41

dotnet add package SweetMock.Extensions.TimeProvider --version 0.9.41
                    
NuGet\Install-Package SweetMock.Extensions.TimeProvider -Version 0.9.41
                    
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="SweetMock.Extensions.TimeProvider" Version="0.9.41" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="SweetMock.Extensions.TimeProvider" Version="0.9.41" />
                    
Directory.Packages.props
<PackageReference Include="SweetMock.Extensions.TimeProvider" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add SweetMock.Extensions.TimeProvider --version 0.9.41
                    
#r "nuget: SweetMock.Extensions.TimeProvider, 0.9.41"
                    
#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.
#:package SweetMock.Extensions.TimeProvider@0.9.41
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=SweetMock.Extensions.TimeProvider&version=0.9.41
                    
Install as a Cake Addin
#tool nuget:?package=SweetMock.Extensions.TimeProvider&version=0.9.41
                    
Install as a Cake Tool

SweetMock.Extensions.TimeProvider

A lightweight extension library for SweetMock for mocking TimeProvider in .NET tests. Control time precisely in your tests without complex setup.

Features

  • Mock TimeProvider: Full control over time in tests using FakeTimeProvider
  • Auto-initialization: Automatically initialized to current UTC time — no setup required
  • Set a Fixed Time: Initialize with a specific DateTimeOffset or FakeTimeProvider
  • Advance Time: Move time forward during a test with Modify
  • Method Chaining: Chain multiple Modify calls for composable time manipulation
  • Timer Support: Test ITimer-based logic by advancing time to trigger callbacks
  • Re-initialization: Reset the clock to a different time mid-test

Installation

dotnet add package SweetMock.Extensions.TimeProvider

Quick Start

Using with Fixtures

[Fixture<MyService>]
public class MyServiceTests
{
    [Fact]
    public void DefaultTimeProvider_UsesCurrentUtcTime()
    {
        // Arrange - no config needed, auto-initialized to UtcNow
        var fixture = Fixture.MyService();
        var sut = fixture.CreateMyService();

        // Act
        var result = sut.GetCurrentTime();

        // Assert
        Assert.True(DateTimeOffset.UtcNow - result < TimeSpan.FromMilliseconds(10));
    }

    [Fact]
    public void TimeProvider_CanBeSetToAFixedTime()
    {
        // Arrange
        var startTime = new DateTimeOffset(2025, 4, 15, 13, 51, 0, TimeSpan.Zero);
        var fixture = Fixture.MyService(config =>
            config.provider.Initialize(startTime)
        );
        var sut = fixture.CreateMyService();

        // Act
        var result = sut.GetCurrentTime();

        // Assert
        Assert.Equal(startTime, result);
    }
}

public class MyService(TimeProvider provider)
{
    public DateTimeOffset GetCurrentTime() => provider.GetUtcNow();
}

Initializing the Time Provider

Default Behavior

Without any configuration, the mock is automatically initialized to the current UTC time at the moment of fixture creation:

var fixture = Fixture.MyService();
var sut = fixture.CreateMyService();

// Time will be very close to DateTimeOffset.UtcNow
var result = sut.GetCurrentTime();

Initialize with a DateTimeOffset

var startTime = new DateTimeOffset(2025, 1, 1, 0, 0, 0, TimeSpan.Zero);
var fixture = Fixture.MyService(config =>
    config.provider.Initialize(startTime)
);

Initialize with a FakeTimeProvider

var fakeTimeProvider = new FakeTimeProvider(new DateTimeOffset(2025, 4, 15, 13, 51, 0, TimeSpan.Zero));
var fixture = Fixture.MyService(config =>
    config.provider.Initialize(fakeTimeProvider)
);

Advancing Time

Use Modify to manipulate the FakeTimeProvider during a test. The Modify method requires the mock to have been initialized with a FakeTimeProvider (either directly or via Initialize).

[Fact]
public void TimeCanBeAdvancedDuringATest()
{
    // Arrange
    var startTime = new DateTimeOffset(2025, 4, 15, 13, 51, 0, TimeSpan.Zero);
    var fixture = Fixture.MyService(config =>
        config.provider.Initialize(startTime)
    );
    var sut = fixture.CreateMyService();

    // Act
    fixture.Config.provider.Modify(t => t.Advance(TimeSpan.FromMinutes(1)));
    var result = sut.GetCurrentTime();

    // Assert
    Assert.Equal(new DateTimeOffset(2025, 4, 15, 13, 52, 0, TimeSpan.Zero), result);
}

Method Chaining

Multiple Modify calls are applied cumulatively and can be chained:

fixture.Config.provider
    .Modify(t => t.Advance(TimeSpan.FromHours(1)))
    .Modify(t => t.Advance(TimeSpan.FromMinutes(30)));

Re-initializing the Clock

You can reset the clock to a completely different time mid-test:

[Fact]
public void TimeProvider_CanBeReInitialized()
{
    // Arrange
    var firstTime = new DateTimeOffset(2025, 1, 1, 0, 0, 0, TimeSpan.Zero);
    var secondTime = new DateTimeOffset(2030, 6, 15, 12, 0, 0, TimeSpan.Zero);
    var fixture = Fixture.MyService(config =>
        config.provider.Initialize(firstTime)
    );
    var sut = fixture.CreateMyService();
    Assert.Equal(firstTime, sut.GetCurrentTime());

    // Act
    fixture.Config.provider.Initialize(secondTime);

    // Assert
    Assert.Equal(secondTime, sut.GetCurrentTime());
}

Timer Support

Advancing time with Modify also triggers any ITimer callbacks registered on the mock:

[Fact]
public void Timers_AreTriggeredByAdvancingTime()
{
    // Arrange
    var triggers = new List<string>();
    var sut = Mock.TimeProvider(out var config);

    // Act
    var timer = sut.CreateTimer(
        state => triggers.Add(state!.ToString()!),
        "tick",
        dueTime: TimeSpan.FromSeconds(1),
        period: TimeSpan.FromSeconds(2)
    );

    config.Modify(t => t.Advance(TimeSpan.FromSeconds(7)));

    // Assert - fires at 1s, 3s, 5s, 7s
    Assert.Equal(4, triggers.Count);
}

Complete Example

[Fixture<SubscriptionService>]
[Mock<TimeProvider, MockOf_TimeProvider>]
public class SubscriptionServiceTests
{
    [Fact]
    public void Subscription_ExpiresAfterThirtyDays()
    {
        // Arrange
        var startTime = new DateTimeOffset(2025, 1, 1, 0, 0, 0, TimeSpan.Zero);
        var fixture = Fixture.SubscriptionService(config =>
            config.provider.Initialize(startTime)
        );
        var sut = fixture.CreateSubscriptionService();
        sut.Activate();

        // Advance time just before expiry
        fixture.Config.provider.Modify(t => t.Advance(TimeSpan.FromDays(29)));
        Assert.True(sut.IsActive());

        // Advance past expiry
        fixture.Config.provider.Modify(t => t.Advance(TimeSpan.FromDays(2)));
        Assert.False(sut.IsActive());
    }
}

public class SubscriptionService(TimeProvider provider)
{
    private DateTimeOffset? _activatedAt;

    public void Activate() => _activatedAt = provider.GetUtcNow();

    public bool IsActive() =>
        _activatedAt.HasValue &&
        provider.GetUtcNow() - _activatedAt.Value < TimeSpan.FromDays(30);
}

API Reference

MockOf_TimeProvider

The main mock class. Extends FakeTimeProviderMockBase and wraps FakeTimeProvider from Microsoft.Extensions.Time.Testing.

// Create directly
var sut = Mock.TimeProvider();

// Create with config
var sut = Mock.TimeProvider(out var config);

// Create with explicit config action
var sut = Mock.TimeProvider(config => config.Initialize(startTime));

MockConfig Methods

// Initialize from a DateTimeOffset
config.Initialize(new DateTimeOffset(2025, 1, 1, 0, 0, 0, TimeSpan.Zero));

// Initialize from a FakeTimeProvider
config.Initialize(new FakeTimeProvider(startTime));

// Initialize from any TimeProvider (copies all settings)
config.Initialize(myTimeProvider);

// Manipulate the underlying FakeTimeProvider
config.Modify(t => t.Advance(TimeSpan.FromSeconds(30)));
config.Modify(t => t.SetLocalTimeZone(TimeZoneInfo.Utc));

// Chain multiple modifications
config.Modify(t => t.Advance(TimeSpan.FromHours(1)))
      .Modify(t => t.Advance(TimeSpan.FromMinutes(30)));

Note: Modify requires the mock to have been initialized with a FakeTimeProvider. Calling it on a mock initialized via a plain TimeProvider will throw NullReferenceException.

Requirements

  • .NET 8.0, 9.0, or 10.0
  • SweetMock
  • Microsoft.Extensions.TimeProvider.Testing

License

See the main SweetMock repository for license information.

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  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.  net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.9.41 131 5/22/2026
0.9.40 119 5/19/2026
0.9.39 128 4/29/2026
0.9.38 107 4/21/2026