我有一些单元测试,期望“当前时间”与DateTime不同。显然,我不想改变电脑的时间。
实现这一目标的最佳策略是什么?
我有一些单元测试,期望“当前时间”与DateTime不同。显然,我不想改变电脑的时间。
实现这一目标的最佳策略是什么?
当前回答
我也有同样的问题,但我在想我们不应该在同一类上使用设置日期时间的东西。因为有一天可能会导致滥用。我使用了提供商
public class DateTimeProvider
{
protected static DateTime? DateTimeNow;
protected static DateTime? DateTimeUtcNow;
public DateTime Now
{
get
{
return DateTimeNow ?? System.DateTime.Now;
}
}
public DateTime UtcNow
{
get
{
return DateTimeUtcNow ?? System.DateTime.UtcNow;
}
}
public static DateTimeProvider DateTime
{
get
{
return new DateTimeProvider();
}
}
protected DateTimeProvider()
{
}
}
对于测试,在测试项目中创建了一个助手来处理设置的事情,
public class MockDateTimeProvider : DateTimeProvider
{
public static void SetNow(DateTime now)
{
DateTimeNow = now;
}
public static void SetUtcNow(DateTime utc)
{
DateTimeUtcNow = utc;
}
public static void RestoreAsDefault()
{
DateTimeNow = null;
DateTimeUtcNow = null;
}
}
在代码
var dateTimeNow = DateTimeProvider.DateTime.Now //not DateTime.Now
var dateTimeUtcNow = DateTimeProvider.DateTime.UtcNow //not DateTime.UtcNow
在测试中
[Test]
public void Mocked_Now()
{
DateTime now = DateTime.Now;
MockDateTimeProvider.SetNow(now); //set to mock
Assert.AreEqual(now, DateTimeProvider.DateTime.Now);
Assert.AreNotEqual(now, DateTimeProvider.DateTime.UtcNow);
}
[Test]
public void Mocked_UtcNow()
{
DateTime utcNow = DateTime.UtcNow;
MockDateTimeProvider.SetUtcNow(utcNow); //set to mock
Assert.AreEqual(utcNow, DateTimeProvider.DateTime.UtcNow);
Assert.AreNotEqual(utcNow, DateTimeProvider.DateTime.Now);
}
但需要记住一件事,有时真正的DateTime和提供程序的DateTime并不相同
[Test]
public void Now()
{
Assert.AreEqual(DateTime.Now.Kind, DateTimeProvider.DateTime.Now.Kind);
Assert.LessOrEqual(DateTime.Now, DateTimeProvider.DateTime.Now);
Assert.LessOrEqual(DateTimeProvider.DateTime.Now - DateTime.Now, TimeSpan.FromMilliseconds(1));
}
我假设差异是maximum TimeSpan.FromMilliseconds(0.00002)。但大多数时候甚至更少
在MockSamples中找到样本
其他回答
摩尔数:
[Test]
public void TestOfDateTime()
{
var firstValue = DateTime.Now;
MDateTime.NowGet = () => new DateTime(2000,1,1);
var secondValue = DateTime.Now;
Assert(firstValue > secondValue); // would be false if 'moleing' failed
}
免责声明-我工作的鼹鼠
模拟对象。
一个模拟DateTime,返回适合您的测试的Now。
下面的代码为我工作:
bizDeedMock.Verify(p => p.SetDeed(It.Is<DsPostList>(x => x.PostLists[0].registerDate.Year == DateTime.Now.Year)));
bizDeedMock.Verify(p => p.SetDeed(It.Is<DsPostList>(x => x.PostLists[0].registerDate.Month == DateTime.Now.Month)));
bizDeedMock.Verify(p => p.SetDeed(It.Is<DsPostList>(x => x.PostLists[0].registerDate.Day == DateTime.Now.Day)));
我很惊讶没有人提出一个最明显的方法:
public class TimeDependentClass
{
public void TimeDependentMethod(DateTime someTime)
{
if (GetCurrentTime() > someTime) DoSomething();
}
protected virtual DateTime GetCurrentTime()
{
return DateTime.Now; // or UtcNow
}
}
然后,您可以简单地在测试double中重写此方法。
在某些情况下,我还喜欢注入一个TimeProvider类,但对于其他情况,这就足够了。不过,如果需要在多个类中重用TimeProvider版本,我可能更喜欢它。
编辑:对于任何感兴趣的人来说,这被称为向类中添加“接缝”,在这个点上,您可以钩入它的行为来修改它(用于测试目的或其他),而无需实际更改类中的代码。
这些都是很好的答案,这是我在另一个项目中所做的:
用法:
获取今天的真实日期时间
var today = SystemTime.Now().Date;
而不是使用DateTime。现在,你需要使用SystemTime.Now()…这并不难改变,但这种解决方案可能并不适合所有项目。
时间旅行(让我们去5年后)
SystemTime.SetDateTime(today.AddYears(5));
获得我们虚假的“今天”(从“今天”开始算起5年)
var fakeToday = SystemTime.Now().Date;
重置日期
SystemTime.ResetDateTime();
/// <summary>
/// Used for getting DateTime.Now(), time is changeable for unit testing
/// </summary>
public static class SystemTime
{
/// <summary> Normally this is a pass-through to DateTime.Now, but it can be overridden with SetDateTime( .. ) for testing or debugging.
/// </summary>
public static Func<DateTime> Now = () => DateTime.Now;
/// <summary> Set time to return when SystemTime.Now() is called.
/// </summary>
public static void SetDateTime(DateTime dateTimeNow)
{
Now = () => dateTimeNow;
}
/// <summary> Resets SystemTime.Now() to return DateTime.Now.
/// </summary>
public static void ResetDateTime()
{
Now = () => DateTime.Now;
}
}