我可以更改特定流程的当前日期和时间吗?

时间:2016-03-07 22:53:17

标签: unit-testing time mocking

是否有办法更改特定进程所看到的日期和时间,而不是整个计算机(即time()在C中返回的时间,DateTime.Now在C#中返回的时间{{ Python中的{1}},JavaScript中的datetime.now(),Java中的new Date()等)?

例如,是否有办法欺骗程序在计算机的其余部分进行午夜时分,或让它认为是圣诞节或跳跃系统时钟显示7月18日那天?

适用的情况是,当您编写单元测试时,您希望快速测试该程序在圣诞节或闰日或演示的到期日期间的任何特殊行为,并且您希望测试此行为,而无需在操作系统中使用日期更改功能,并干扰依赖日期正确的程序(更不用说强迫我通过计算机拥有超级用户权限)。

4 个答案:

答案 0 :(得分:2)

我认为你不能在C#中做你想做的事。我知道没有任何钩子使DateTime.Now能够立即返回任意值。实现时间敏感的单元测试的标准方法是创建时间提供者接口。这是第三方库(例如Noda Time)采用的方法,它重视测试时间相关的功能。下面是一个这样的实现(不是Noda Time兼容):

public ITimeProvider
{
    DateTime CurrentTime { get; }
    DateTime CurrentUtcTime { get; }
}

public DefaultTimeProvider : ITimeProvider
{
    public DateTime CurrentTime { get { return DateTime.Now; } }
    public DateTime CurrentUtcTime { get { return DateTime.UtcNow; } }
}

然后,当您想要对代码进行单元测试时,可以使用模拟实现替换DefaultTimeProvider实现。您可以使用自己喜欢的模拟框架,或者只写下这样的内容:

public MockTimeProvider : ITimeProvider
{
    private readonly DateTime _currentTime;
    private readonly DateTime _currentUtcTime;

    public MockTimeProvider(DateTime currentTime, DateTime currentUtcTime)
    {
        _currentTime = currentTime;
        _currentUtcTime = currentUtcTime;
    }

    public DateTime CurrentTime { get { return _currentTime; } }
    public DateTime CurrentUtcTime { get { return _currentUtcTime; } }
}

答案 1 :(得分:2)

免责声明,我在Typemock工作。

您可以使用Typemock Isolator

[TestMethod]
public void isLicenseExpiredTest()
{
    Isolate.WhenCalled(() => DateTime.Now).WillReturn(new DateTime(2017, 5, 4));

    bool result = Licenses.IsLicenseExpired();

    Assert.IsFalse(result);
}

public static class Licenses
{
    public static bool IsLicenseExpired()
    {

        if (DateTime.Now > new DateTime(2016, 5, 4))
        {
            return false;
        }
        else
        {
            return true;
        }
    }
}

答案 2 :(得分:2)

之前提到的Typemock还有一个API用于C ++,它还允许你在C ++中伪造时间:

TEST_METHOD(FakeCurrentTime)
{
    SYSTEMTIME fakeTime;
    fakeTime.wYear = 2000;
    fakeTime.wMonth = 1;
    fakeTime.wDay = 1;

    FAKE_GLOBAL(GetSystemTime);
    WHEN_CALLED(GetSystemTime(RET(&fakeTime))).Ignore();

    SYSTEMTIME now;
    GetSystemTime(&now);

    Assert::IsTrue(now.wMilliseconds - fakeTime.wMilliseconds == 0);
}

答案 3 :(得分:1)

java.time

Java 8及更高版本内置了java.time框架。支持旧的日期时间类。

Clock

包括Clock课程。您可以覆盖此类以创建自己的伪造当前时间。

通过静态方法包含一些替代实现。您可以要求在您指定的单个时刻保持固定的Clock。您可以将当前时间移动一些指定的量。你有时钟报告当前时刻四舍五入到整秒或分钟等等。