如何在 .NET 中操作 DateTime 以帮助您更好地编码

好的,我将取消夸张,作为一名工程师,在我这么多年(读到我感觉自己老了)时,我遇到了一个问题,我的代码包含一个DateTime.Nowor DateTime.UtcNow。当我编写测试时,我无法验证实际时间,因为从代码运行到我的测试开始验证已经过去了几毫秒。这不是一个大问题,但很烦人,因为我喜欢验证所有内容以确保我不会意外地在其他地方操纵这些值。

对此有一个简单的解决方案,在我详细说明我使用的解决方案之前,我需要指出这方面的灵感。TL;DR 是您可以使用我的SimpleDateTimeProvider NuGet 包来帮助您解决这个问题。代码的实现如下。


解决方案

我创建了一个DateTimeProvider由一个接口和两个接口实现组成的。一种实现返回系统值,另一种返回用户预设的模拟值。

界面

public interface IDateTimeProvider
{
    DateTime Now { get; }
    DateTime Today { get; }
    DateTime UtcNow { get; }
}

系统实现

public class SystemDateTimeProvider : IDateTimeProvider
{
    public DateTime Now => DateTime.Now;
    public DateTime Today => DateTime.Today;
    public DateTime UtcNow => DateTime.UtcNow;
}

模拟实现

public class MockDateTimeProvider : IDateTimeProvider
{
    public DateTime Now
    {
        get => this.now.ThrowIfNotSet(DateTimeType.Now);
        set => this.now = value;
    }
    public DateTime Today
    {
        get => this.today.ThrowIfNotSet(DateTimeType.Today);
        set => this.today = value;
    }
    public DateTime UtcNow
    {
        get => this.utcNow.ThrowIfNotSet(DateTimeType.UtcNow);
        set => this.utcNow = value;
    }
}

折弯日期和时间

这是一个简单的解决方案,使用提供程序很容易上手,只需IDateTimeProvider在功能代码中的接口下注入系统提供程序即可。如果您使用的是另一个库,您会知道语法但遵循相同的公式。

_ = services.AddSingleton<IDateTimeProvider, SystemDateTimeProvider>();

下一步是创建你的类并使用SystemDateTimeProvider我们刚刚通过IDateTimeProvider接口创建的注册。然后使用提供程序DateTime在您的类中设置值。

public class Service
{
    private readonly IDateTimeProvider dateTimeProvider;

    public Service(IDateTimeProvider dateTimeProvider)
    {
        this.dateTimeProvider = dateTimeProvider;
    }

    public string DateTimeNow()
    {
        return $"DateTime.Now is {this.dateTimeProvider.Now}";
    }
}

这样做的全部目的是允许可测试的代码。所以现在你有了上面的类,你可以MockDateTimeProvider在它的位置注入来控制DateTime测试中的值。以下示例展示了如何在 XUnit 中编写测试使用Shouldly进行断言。

[Fact]
public void Today_ShouldReturn_MockedToday()
{
    // Arrange
    var provider = new MockDateTimeProvider();
    var service = new Service(provider);
    var today = DateTime.Today;

    provider.Today = today;

    // Act
    var result = service.DateTimeToday();

    // Assert
    _ = result.ShouldBeOfType<string>();
    result.ShouldBe($"DateTime.Today is {today}");
}

我在哪里可以找到这个?

所有这些都是开源的。
您可以在SimpleDateTimeProvider Repository的GitHub 上找到我的工作,并在SimpleDateTimeProvider NuGet上找到已发布的包。


支持

如果你喜欢这个,请查看我在GitHub 上的其他示例,并考虑在Buy Me a Coffee上支持我。