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

时间:2010-02-17 20:49:10

标签: c# unit-testing

我有这种方法取决于当前日期。它检查今天是太阳,周一,周二还是周三,然后它给出了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; 
}

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

8 个答案:

答案 0 :(得分:19)

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

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之间发生变化。

答案 1 :(得分:10)

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

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)。

答案 2 :(得分:3)

让您的课程采用IClock参数(通过构造函数或属性)

interface IClock
{
    DateTime Now { get; }
}

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

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

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

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

答案 3 :(得分:1)

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

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

答案 4 :(得分:0)

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

答案 5 :(得分:0)

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

答案 6 :(得分:0)

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

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

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; 
}

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

答案 7 :(得分:0)

我建议将其作为Mark suggests执行此操作,但添加了一个生成使用的重载调用,该调用不使用任何参数并使用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; 
}