UnitTest是一种与时间相关的方法

时间:2013-07-03 13:10:41

标签: c# .net unit-testing

您如何测试与时间相关的方法?

一个简单的例子可能是:

public static int GetAge(DateTime birthdate)
{
    // ...
}

[TestMethod]
public void GetAgeTest()
{
    // This is only ok for year 2013 !
    Assert.AreEqual(GetAge(new DateTime(2000, 1, 1)), 13);
}

问题在于它仅适用于本年度(在本案例中为2013年)。新的一年开始,我必须重写所有依赖于时间的测试......

单元测试这种方法的最佳方法是什么?

7 个答案:

答案 0 :(得分:4)

您可以覆盖GetAge方法找到今天日期的机制。

如果将DateTime包装在另一个类中,则可以使用在单元测试时返回已知值的虚假调用替换实际调用。

您可以使用依赖注入在生产的实际实现和用于测试的虚假实现之间切换。

答案 1 :(得分:3)

另外,不要忘记“预期”参数是AreEquals中的第一个参数。

[TestMethod]
public void GetAgeTest()
{
    int age = 13;
    Assert.AreEqual(age, GetAge(DateTime.Now.AddYears(age * -1));
}

在安排 - 行动 - 断言这样的小组中分开测试也会更好:

[TestMethod]
public void GetAgeTest()
{
    // Arrange
    int age = 13;

    // Act
    int result = GetAge(DateTime.Now.AddYears(age * -1);

    // Assert
    Assert.AreEqual(age, result);
}

答案 2 :(得分:2)

两个主要选项:

  1. 创建一个隔离时间相关功能的服务,并将其接口注入需要它的类中。然后,您可以模拟此界面以获得测试所需的行为。

  2. 使用像Moles这样的绕道测试框架(还有一些其他的)可以重新路由静态方法调用,如DateTime.Now

答案 3 :(得分:1)

这样的事情可以解决问题

var birthDate = new DateTime(DateTime.Now.Year - 13, 1, 1)
int age = GetAge(birthDate);
Assert.AreEqual(age, 13);

答案 4 :(得分:1)

另一种解决方案是使用Microsoft Shims和Fakes。 看http://msdn.microsoft.com/en-us/library/hh549175.aspx

using (ShimsContext.Create())
{
    // Shim DateTime.Now to return a fixed date:
    System.Fakes.ShimDateTime.NowGet = () =>
    { 
        return new DateTime(fixedYear, 1, 1); 
    };
}

答案 5 :(得分:0)

在这种特定情况下,也许不是最佳选择,但您也可以将函数的界面扩展为还需要传递DateTime now

public static int GetAge(DateTime birthdate, DateTime now)
{
    // ...
}

[TestMethod]
public void GetAgeTest()
{
    Assert.AreEqual(GetAge(new DateTime(2000, 1, 1), new DateTime(2013, 1, 1)), 13);
}

您基本上将当前日期的责任委托给调用者(尽管也推动了单元测试问题)。

一个好的副作用是你真的得到一个明确定义的#34;现在"在这个功能的范围内。在ticks级别,调用DateTime.Now的时刻会产生影响。您可以在抽象级别描述该函数为"给定此生日和当前日期,年龄为"。

同样,这可能不是每种情况下最好的方式,但我认为在某些情况下值得考虑。

答案 6 :(得分:0)

另一种解决方案是使用VirtualTime。 ,它简化了单元测试时间依赖的应用程序,请参阅此处的使用和示例Unit Testing: DateTime.Now