如何测试依赖于当前日期的逻辑

我有这种方法取决于当前日期。 它检查今天是太阳,周一,周二还是周三,然后它给出了5天的交货时间。 如果它是星期四,星期五或星期六那么它给出了6天的交付周期来计算周末。

private DateTime GetEstimatedArrivalDate() { DateTime estimatedDate; if (DateTime.Now.DayOfWeek >= DayOfWeek.Thursday) { estimatedDate = DateTime.Now.Date.AddDays(6); } else { estimatedDate = DateTime.Now.Date.AddDays(5); } return estimatedDate; } 

实际的估算逻辑更复杂。 为了这个问题,我简化了它。 我的问题是如何根据今天的日期为这样的事情编写unit testing?

您需要将当前日期作为参数传递:

 private DateTime GetEstimatedArrivalDate(DateTime currentDate) { DateTime estimatedDate; if (currentDate.DayOfWeek >= DayOfWeek.Thursday) { estimatedDate = currentDate.AddDays(6); } else { estimatedDate = currentDate.AddDays(5); } return estimatedDate; } 

在实际代码中,您可以这样称呼它:

 DateTime estimatedDate = GetEstimatedArrivalDate(DateTime.Now.Date); 

然后你可以测试它如下:

 DateTime actual = GetEstimatedArrivalDate(new DateTime(2010, 2, 10)); DateTime expected = ...; // etc... 

请注意,这也修复了程序中潜在的错误,其中日期在连续调用DateTime.Now之间发生变化。

一般来说,您需要抽象获取接口背后的当前日期和时间的方法,例如:

 public interface IDateTimeProvider { DateTime Now { get; } } 

真正的服务是:

 public class DateTimeProvider: IDateTimeProvider { public DateTime Now { get { return DateTime.Now; } } } 

测试服务将是:

 public class TestDateTimeProvider: IDateTimeProvider { private DateTime timeToProvide; public TestDateTimeProvider(DateTime timeToProvide) { this.timeToProvide = timeToProvide; } public DateTime Now { get { return timeToProvide; } } } 

对于需要当前时间的服务,让他们将IDateTimeProvider作为依赖项。 对于真实的东西,传递一个新的DateTimeProvider(); 当你是一个组件时,传入一个新的TestDateTimeProvider(timeToTestFor)。

让你的类采用IClock参数(通过构造函数或属性)

 interface IClock { DateTime Now { get; } } 

然后,您可以使用虚假实现进行测试

 class FakeClock : IClock { DateTime Now { get; set } } 

并在其余时间实现真正的实施。

 class SystemClock : IClock { DateTime Now { get { return DateTime.Now; } } } 

我会给出有争议的答案,不要测试它。

逻辑是微不足道的,并且它具有零依赖性,我相信良好的代码覆盖率,但是当它增加复杂性而没有真正的增益时。

似乎有足够多的案例你可以明确地测试它们。 该方法取决于今天的日期,但输出仅取决于星期几,每个日期都有一周中的某一天。

您可以传入一个在正常执行期间返回DateTime.Now的委托,然后在另一个返回固定日期的委托中的测试传递中传入,并根据该委托断言您的结果。

我建议按照Mark的建议这样做,但是为生产使用添加了一个重载调用,它不带任何参数并使用DateTime.Now

 private DateTime GetEstimatedArrivalDate() { return GetEstimatedArrivalDate(DateTime.Now); } private DateTime GetEstimatedArrivalDate(DateTime currentDate) { DateTime estimatedDate; if (currentDate.DayOfWeek >= DayOfWeek.Thursday) { estimatedDate = currentDate.AddDays(6); } else { estimatedDate = currentDate.AddDays(5); } return estimatedDate; } 

这样做的一种“常见”方式是“伪造”当前系统日期(可以通过多种方式完成),然后在“已知”日期测试代码。

另一个有趣的方法是将您的实现稍微改为:

 private DateTime GetEstimatedArrivalDate() { return GetEstimatedArrivalDate(DateTime.Now); } private DateTime GetEstimatedArrivalDate(DateTime forDate) { DateTime estimatedDate; if (forDate.DayOfWeek >= DayOfWeek.Thursday) { estimatedDate = forDate.Date.AddDays(6); } else { estimatedDate = forDate.Date.AddDays(5); } return estimatedDate; } 

然后使用带参数的方法测试“立即”日期。