我有一个连续的测试管道,在代码能够合并之前,单元和集成测试必须通过PR。
它在减少错误和稳定我们的代码库方面做得很好,但我们遇到了时间问题。
在周末,组成该堆栈的几个应用程序都有明确的检查,不允许在周末提交新订单。更糟糕的是,其中一些应用程序使用了DateTime。现在,对于这些检查,如果没有大型重构,就无法进行模拟。
在c#中,是否可以在我们的测试中发出一个命令来更新"服务器时间",这样我们的大多数测试都可以工作?
试试这个。
也就是说,使用适当的数据结构调用WinAPI函数SetSystemTime
。
不要忘记将服务器时间返回到"0";正确的"!
[当然,假设你的服务器是Windows,你没有提到…]
简单的答案是否定的。如果你想围绕一些基本界面进行调整,你要么需要在测试运行前设置操作系统并更改时间(这可能会产生非常不可预测的结果(,要么模拟它。实际上很简单:
不要使用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);
如果您的是独立于应用程序的可执行文件/服务,您可以传递一个参数来设置此管理器的初始值:
myapp.exe--开始日期"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
在这种情况下,控制权倒置是你最好的朋友。
我得出的结论是,将操作系统特定的方法替换为我自己的接口比在测试环境中进行黑客攻击更容易。例如,在我的项目中,所有的File
名称空间经常因为同样的原因而被嘲笑。我可以用这种方式模仿任何行为。