如何从 C# 代码动态更新服务器时间

How can I update the server time dynamically from c# code

我有一个连续的测试管道,单元测试和集成测试必须在代码能够合并之前通过 PR。

它在减少错误和稳定我们的代码库方面做得很好,但我们在时间上遇到了问题。

在周末,组成此堆栈的几个应用程序会进行明确检查,以防止在周末提交新订单。更糟糕的是,其中一些应用程序使用 DateTime.Now 进行这些检查,如果不进行大量重构就无法模拟。

是否可以在 c# 中在我们的测试中发出一个命令来更新“服务器时间”,以便我们的大多数测试都能正常工作?

简短的回答是否定的。如果您想调整一些基本界面,您需要设置 OS 并在测试运行前更改时间(这可能会产生非常不可预测的结果)或模拟它。其实很简单:

而不是使用 DateTime。Now/UtcNow 使用您的显式版本。

public interface IDateTimeManager
{
    DateTime Now {get;}
}

代码库中的任意位置:

var now = _dateTimeManager.Now;

在测试设置中:

var mockDateTimeManager = new Mock<IDateTimeManager>();
mockDateTimeManager.Setup(x=> x.Now).Returns(new DateTime(2000,1,1));

在 di 设置中:

var container = new Container();
container.RegisterSingleton<IDateTimeManager>(mockDateTimeManager.Object);

如果你的应用程序是独立的executable/service,你可以传递一个参数来设置这个管理器的初始值:

myapp.exe --start-date "2000-01-01"

public interface IDateTimeManager
{
    DateTime UtcNow { get; }
}
internal sealed class DateTimeManager : IDateTimeManager
{
    private readonly DateTime _initialTime;
    private readonly DateTime _initialOsTime;
    public DateTime UtcNow => _initialTime + (DateTime.UtcNow - _initialOsTime);

    public DateTimeManager(DateTime initialTime)
    {
        _initialTime = initialTime;
        _initialOsTime = DateTime.UtcNow;

    }
}

PS

在这种情况下,控制反转是你最好的朋友。

我得出的结论是,将 OS 特定方法替换为我自己的接口更容易,而不是绕过测试环境。例如,在我的项目中,出于同样的原因,所有 File 命名空间经常被模拟。我可以通过这种方式模拟任何行为。

Try this.

也就是说,使用适当的数据结构调用 WinAPI 函数 SetSystemTime

不要忘记return服务器时间“更正”!

[假设,当然,你的服务器是Windows,你没有提到...]