如何从 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,你没有提到...]
我有一个连续的测试管道,单元测试和集成测试必须在代码能够合并之前通过 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,你没有提到...]