如何测试依赖于当前日期的逻辑
我有这种方法取决于当前日期。 它检查今天是太阳,周一,周二还是周三,然后它给出了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; }
然后使用带参数的方法测试“立即”日期。