C# “怎么可能?”;今天';“s日期”;为了单元测试的目的可以改变吗?

C# “怎么可能?”;今天';“s日期”;为了单元测试的目的可以改变吗?,c#,unit-testing,datetime,C#,Unit Testing,Datetime,我使用VS2008瞄准.NET 2.0框架,以防万一,不,我无法更改此项:) 我有一个DateCalculator课程。它的方法getnextexirationdate尝试在内部使用DateTime.Today作为基线日期来确定下一个过期日期 在编写单元测试时,我意识到我想测试不同的“今天”日期的getnextexirationdate 最好的方法是什么?以下是我考虑过的一些备选方案: 公开带有参数baselineDate的属性/重载方法,并仅从单元测试中使用它。在实际的客户机代码中,忽略属性

我使用VS2008瞄准.NET 2.0框架,以防万一,不,我无法更改此项:)

我有一个
DateCalculator
课程。它的方法
getnextexirationdate
尝试在内部使用
DateTime.Today
作为基线日期来确定下一个过期日期

在编写单元测试时,我意识到我想测试不同的“今天”日期的
getnextexirationdate

最好的方法是什么?以下是我考虑过的一些备选方案:

  • 公开带有参数
    baselineDate
    的属性/重载方法,并仅从单元测试中使用它。在实际的客户机代码中,忽略属性/重载方法,而使用默认值
    baselineDate
    DateTime.Today
    的方法。我不愿意这样做,因为这会使DateCalculator类的公共接口变得笨拙
  • 创建一个名为
    baselineDate
    的受保护字段,该字段在内部设置为
    DateTime.Today
    。测试时,从
    DateCalculator
    导出用于测试的
    DateCalculator,并通过构造函数设置
    baslineDate
    。它保持了公共接口的整洁,但仍然不是很好-
    baselineDate
    受到了保护,并且需要一个派生类,这两者都只是为了测试
  • 使用扩展方法。在添加了
    扩展属性之后,我尝试了这个方法,然后意识到它不起作用,因为扩展方法无法访问私有/受保护的变量。我最初认为这是一个非常优雅的解决方案(

我很想听听其他人的想法。

您可以使用一个提供基线日期的接口。通常您会使用一个返回日期时间的实现。今天,为了测试的目的,可以使用一个让您的单元测试提供日期的实现

如果有必要在数据库服务器或其他不一定运行代码的机器上使用当前日期,这也很有用


事实上,这里有一些比我更详细的答案的问题:

一个选项是创建一个需要日期时间的内部重载,并将真正的实现委托给它:

public DateTime GetNextExpirationDate()
{
  return GetNextExpirationDate(DateTime.Today);
}

internal DateTime GetNextExpirationDate(DateTime after)
{
  // implementation goes here
}

然后,您可以使用InternalsVisibleToAttribute使重载对您的测试程序集可见,然后您的测试程序集可以使用自己选择的DateTime值调用它。

您可以在进行测试的计算机上更改操作系统的时间时钟。这很简单,也很透明,但请注意以下问题:文件时间戳。

我通常在抽象/接口中收集对操作系统的调用,这样我就可以很容易地测试它。正如上面提到的那样

然而,仅考虑到问题中提到的需求,我觉得“子类和重写”是完成此任务的最简单和最不具侵入性的方法——OP提到的选项2

public class DateCalculator
{
  public DateTime GetNextExpirationDate() {  // call to GetBaseLineDate() to determine result }
  virtual protected GetBaseLineDate() {  return DateTime.Today; }
}

// in your test assembly
public class DateCalcWithSettableBaseLine : DateCalculator
{
  public DateTime BaseLine { get; set;}
  override protected GetBaseLineDate()
  {    return this.BaseLine;  }
}

好问题…如果你要等到某个特定的日期才发现你的测试失败,那将是一件很有趣的事情,因为你依赖于“今天”而不能增加它:)重复:谢谢所有的输入。日期时间提供者方法也是我应该考虑的。然而,在这种情况下,我想我会采用Gishu的方法——它似乎对我来说是最有效、最不具侵入性的方法。