单元测试基于时间的组件?

时间:2010-06-25 08:56:39

标签: c# unit-testing datetime

所以我正在编写一个缓存系统(不是太复杂,但它有非常好的语义)和ttl(生存时间)的项目。

当然ttl必须经过单元测试,但由于无法在C#中注入“IDateTime”或“ITimeSpan”的新实现(因为没有这样的东西),你会怎么做?

首先编写一个新的组件“IDateTimeProvider”和“DateTimeProvider”,然后哪个可以模拟?

是不是重新实现了.NET运行时库的一部分......难以理解?

编辑:谢谢大家的惊人答案!我现在知道我要做什么了!

5 个答案:

答案 0 :(得分:6)

我通常使用Ayende's solution的变体。

public static class SystemTime
{
    public static Func<DateTime> DateProvider = () => DateTime.Now;

    public static DateTime Now { get { return DateProvider(); } }
}

在测试代码中,您现在可以使用SystemTime.Now获取当前时间:

var currentTime = SystemTime.Now;

在测试中,您可以将当前时间设置为已知值:

SystemTime.DateProvider = () => new DateTime(2010,6,25);

答案 1 :(得分:4)

如何编写IDateTimeProvider重新实现.Net Framework的部分内容?

你只有两个实现,一个返回DateTime.Now,另一个返回你之前指定的值。

答案 2 :(得分:3)

您可能希望看到这个问题:

How do I MOQ the System.IO.FileInfo class... or any other class without an interface?

简而言之,您需要自己创建一个包装类,或者使用已经为DateTime提供包装类的库,例如SystemWrapper

答案 3 :(得分:2)

IDateTime提供程序可能在其他方面证明是有用的 - 如果要在运行在不同计算机上的客户端和服务器应用程序之间使用缓存,则两台计算机(通常是服务器)只需一个时间源,否则时间可能不合时宜。 我到处都使用IDateTimeProvider接口,然后客户端可以使用从服务器获取时间的版本。

你会得到 plus 单元测试解耦。

答案 4 :(得分:2)

如果您在发明一些模型对象时遇到问题,我认为重新考虑组件的可测试性是很好的。

也许ttl逻辑应该可以自己测试,有点像这样:

TTLlogic l = new TTLLogic( 10 );
DateTime startdate = now();
Object item=new String();
l.addItem( startdate, item );

l.setTime( startdate.addSeconds( 5 ) );
assert( l.items().contains( item ) );

l.setTime( startdate.addSeconds( 10 ) );
assert( l.items().empty() );