我在C#中构建了一个Windows服务,它根据当前日期和时间从数据库调用实时时间序列数据。
我在测试数据库中有测试数据,我想用它来计算数据是否以正确的方式使用。
我想知道是否有人使用过应用程序或有任何其他方法在本地计算机上“模拟”系统日期。例如,我可以运行此应用程序并将其设置为将系统日期设置为指定日期。
任何建议都会很棒。
答案 0 :(得分:10)
只需封装您对界面后面DateTime.Now
属性的访问权限。
public interface IDateTimeProvider
{
DateTime Now { get; }
}
在您的代码中,使用如下实现:
public class DateTimeProvider : IDateTimeProvider
{
public DateTime Now { get { return DateTime.Now; } }
}
对于您的测试,您可以通过创建测试类或使用模拟框架来模拟IDateTimeProvider
。
如果将此接口与依赖注入等技术一起使用,即使在运行时也很容易改变服务的行为。
你可以,例如创建一个总是休息一小时的IDateTimeProvider
:
public class AlwaysToLateDateTimeProvider : IDateTimeProvider
{
public DateTime Now { get { return DateTime.Now.AddHours(-2); } }
}
或创建一个从文件,数据库,管道等读取“模拟”日期时间的实现。
在测试时,您将配置您的服务以使用其中一个实现,并且在实时模式下运行时,只需配置您的依赖注入以使用返回“正确”日期时间的普通实现。
当然有TypeMock Isolator ...
Isolate.WhenCalled(() => DateTime.Now).WillReturn(new DateTime(2008, 1, 1));
答案 1 :(得分:4)
我已经使用它现在能够覆盖,例如在运行测试时。在您使用DateTime.Now的实际实现中,您使用新的SystemTime.Now。在测试中,您只需将Now设置为另一个返回所选值的函数。
public static class SystemTime
{
private static Func<DateTime> now = () => DateTime.Now;
public static Func<DateTime> Now
{
get { return now; }
set { now = value; }
}
}
测试中的示例用法:
SystemTime.Now = () => DateTime.Now.AddMinutes(20);
在单元测试拆解中,使用SystemTime.Now = () => DateTime.Now
正常使用:
DateTime now = SystemTime.Now();
答案 2 :(得分:0)
与Mharlin的解决方案非常相似,下面的实现提供了DateTime.Now
的一对一替代。添加的是一些在单元测试中操纵时间的便捷方法。修改后的内容是需要显式执行返回DateTime
的操作,该操作更类似于DateTime.Now
用法。
public static class SystemTime
{
private static Func<DateTime> now = () => DateTime.Now;
public static DateTime Now
{
get { return now(); }
}
public static void Set(DateTime dt)
{
now = () => dt;
}
public static void MoveForward(TimeSpan ts)
{
var dt = now().Add(ts);
Set(dt);
}
public static void Reset()
{
now = () => DateTime.Now;
}
}
生产代码中的示例用法:
var twentyMinutesFromNow = SystemTime.Now.AddMinutes(20);
时间敏感测试中的示例用法(此验证缓存过期):
// Set(): effectively lock the system clock at a specific time
SystemTime.Set(new DateTime(2015, 1, 1));
RunCodeThatFetchesDataAndCachesIt();
// MoveForward(): easily move the clock relative to current time with an
// arbitrary TimeSpan
SystemTime.MoveForward(TimeSpan.FromMinutes(1));
RunCodeThatFetchesDataAndCachesIt();
VerifyExpectationThatDataWasFetchedTwice();
// Reset(): return to the normal behavior of returning the current
// DateTime.Now value
SystemTime.Reset();