5

I have built a Windows Service in C# that calls live timeseries data from a database based on the current date and time.
I have test data in a test Databse that I would like to use to calculate if the data was being used in the correct way.
I was wondering if anyone has used an application or has any other way to "Mock" the system date on your local computer. So for example I can just run this application and set it to set my system date to a specified date.

Any advice would be great.

4

3 回答 3

12

只需将您对DateTime.Now属性的访问封装在接口后面。

public interface IDateTimeProvider
{
    DateTime Now { get; }
}

在您的代码中,使用如下实现:

public class DateTimeProvider : IDateTimeProvider
{
    public DateTime Now { get { return DateTime.Now; } }
}

对于您的测试,您可以IDateTimeProvider通过创建测试类或使用模拟框架来模拟。

如果您将此接口与依赖注入之类的技术一起使用,那么即使在运行时也可以轻松更改服务的行为。

例如,您可以创建一个IDateTimeProvider总是休息几个小时的:

public class AlwaysToLateDateTimeProvider : IDateTimeProvider
{
    public DateTime Now { get { return DateTime.Now.AddHours(-2); } }
}

或创建一个从文件、数据库、管道等中读取“模拟”日期时间的实现。

在测试时,您可以将服务配置为使用其中一种实现,并且在实时模式下运行时,只需将依赖注入配置为使用返回“正确”日期时间的普通实现即可。


当然还有TypeMock 隔离器...

Isolate.WhenCalled(() => DateTime.Now).WillReturn(new DateTime(2008, 1, 1));
于 2012-06-19T11:30:21.000 回答
4

我现在已经使用它来覆盖,例如在运行测试时。在您使用 DateTime.Now 的实际实现中,您使用新的 SystemTime.Now 代替。在您的测试中,您只需将 Now 设置为返回您选择的值的不同函数。

public static class SystemTime
{
    private static Func<DateTime> now = () => DateTime.Now;

    public static Func<DateTime> Now
    {
        get { return now; }
        set { now = value; }
    }
}

测试中的示例用法:

SystemTime.Now = () => DateTime.Now.AddMinutes(20);

在单元测试拆解中,将其设置回来很重要SystemTime.Now = () => DateTime.Now

正常使用:

DateTime now = SystemTime.Now();
于 2012-06-19T10:56:20.820 回答
0

与 Mharlin 的解决方案非常相似,下面的实现提供了DateTime.Now. 添加了一些在单元测试中操纵时间的便捷方法。修改的是需要显式执行返回 a 的操作DateTime,这更类似于DateTime.Now用法。

public static class SystemTime
{
    private static Func<DateTime> now = () => DateTime.Now;

    public static DateTime Now
    {
        get { return now(); }
    }

    public static void Set(DateTime dt)
    {
        now = () => dt;
    }

    public static void MoveForward(TimeSpan ts)
    {
        var dt = now().Add(ts);
        Set(dt);
    }

    public static void Reset()
    {
        now = () => DateTime.Now;
    }
}

生产代码中的示例用法:

var twentyMinutesFromNow = SystemTime.Now.AddMinutes(20);

时间敏感测试中的示例用法(这个验证缓存过期):

// Set(): effectively lock the system clock at a specific time
SystemTime.Set(new DateTime(2015, 1, 1));

RunCodeThatFetchesDataAndCachesIt();

// MoveForward(): easily move the clock relative to current time with an
//  arbitrary TimeSpan
SystemTime.MoveForward(TimeSpan.FromMinutes(1));

RunCodeThatFetchesDataAndCachesIt();
VerifyExpectationThatDataWasFetchedTwice();

// Reset(): return to the normal behavior of returning the current
//   DateTime.Now value
SystemTime.Reset();
于 2015-08-18T08:34:37.370 回答