首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >时光机服务

时光机服务
EN

Code Review用户
提问于 2014-04-25 02:22:05
回答 3查看 875关注 0票数 6

最近,有人给我描述了一个“时间机器”服务,也就是可以用来改变代码块对时间的感知方式的服务。

通常,通过调用DateTime.Now和其他DateTime静力学,时间直接与系统时钟联系在一起。使用时间机器服务代替静态DateTime调用,并允许外部代码更改其报告时间。这在为服务编写单元测试时尤其有用,这些服务由于计时器、触发器等原因而随时间的推移而不同。

我喜欢这个想法,并决定实现我自己的版本。以下是相关的接口:

代码语言:javascript
复制
// A service that can travel through time
public interface ITimeTraveler
{
    ITimeMachine TimeMachine { get; set; }
}

// Interface for a Time Machine
public interface ITimeMachine
{
    DateTime Now();
    DateTime UtcNow();
    DateTime Today();
    DateTime UtcToday();
    void TimeTravel(TimeSpan adjustment);
    void TimeTravelTo(DateTime newDateTime);
    void FreezeTime();
    void UnfreezeTime();
    void RevertAllTimeTravel();
    bool IsCurrentlyTimeTraveling();
}

下面是具有完整实现的时光机原理

这包括两次修订。第一个修订是我最初链接到的代码,另外的修订考虑到了这里的反馈。

我正在寻找关于这个服务的概念和我目前的实现的任何反馈或建议。

EN

回答 3

Code Review用户

回答已采纳

发布于 2014-04-25 02:55:27

我喜欢它。

对于某些非常特殊的情况,类需要测试,其功能取决于System.DateTime.Now返回的内容,那么如果您希望能够编写完全控制该依赖项的单元测试,则需要一个抽象来包装静态方法调用。

你的ITimeMachine做得很好。虽然IDateTimeService是一个有意义的名称,但它似乎更适合泛化。ITimeTraveler可能是多余的。

相关代码如下所示:

代码语言:javascript
复制
public class MyClass
{
    private readonly IDateTimeService _service;

    public MyClass(IDateTimeService service)
    {
        _service = service;
    }

    public void DoSomething()
    {
        var now = _service.Now(); // instead of DateTime.Now;
        //...
    }
}

我也喜欢你让Now()成为一种方法。它抽象出了一个事实,即DateTime.Now实际上是一种适用于属性的方法。

票数 4
EN

Code Review用户

发布于 2014-04-25 04:32:49

我猜是:

  • 正在测试的代码使用这些方法: DateTime Now();DateTime UtcNow();DateTime Now();DateTime UtcToday();
  • 这些方法不是被被测试的代码调用的,而是由单元测试代码调用的--测试代码(设置正在测试的代码所经历的'now‘)、void TimeTravel(TimeSpan调整)、void TimeTravelTo(DateTime NewDateTime)、void FreezeTime()、void UnfreezeTime()、void RevertAllTimeTravel()、bool IsCurrentlyTimeTraveling();

因此,后一种方法不需要在这个接口中(传递给正在测试的代码)。这些方法可以放在单独的接口中(只有单元测试代码才知道),也可以只是TimeMachine类的方法。

票数 4
EN

Code Review用户

发布于 2014-04-25 14:06:49

Implementation

我的另一个答案只涉及原来的界面(S)。这一点突出了我在实现中注意到的一点。

代码语言:javascript
复制
/// <summary>
/// Retrieve the current date and time.
/// </summary>
public DateTime Now()
{
    return FrozenDateTime != null 
        ? FrozenDateTime.Value 
        : DateTime.Now.Add(Offset);
}

/// <summary>
/// Move to the specific point in time provided.
/// </summary>
/// <param name="newDateTime">The point in time to move to.</param>
public void TimeTravelTo(DateTime newDateTime)
{
    Offset = newDateTime.Subtract(DateTime.Now);
}

我很想看到它的作用,所以我写了一个小小的测试:

代码语言:javascript
复制
class Program
{
    static void Main(string[] args)
    {
        var service = new TimeMachine();
        Console.WriteLine("Current time is: {0} (system time is: {1})", service.Now(), DateTime.Now);

        //service.FreezeTime();
        //Console.WriteLine("Time frozen at: {0}", service.Now());

        Thread.Sleep(2000);
        Console.WriteLine("Slept for 2000ms.");

        Console.WriteLine("Current time is: {0} (system time is: {1})", service.Now(), DateTime.Now);

        service.TimeTravelTo(DateTime.Now.AddHours(1));
        Console.WriteLine("Time-traveled 1 hour into the future.");

        Console.WriteLine("Current time is: {0} (system time is: {1})", service.Now(), DateTime.Now);

        service.UnfreezeTime();
        Console.WriteLine("Time unfrozen.");

        Console.WriteLine("Current time is: {0} (system time is: {1})", service.Now(), DateTime.Now);
        Console.ReadLine();
    }
}

输出:

如果我取消对FreezeTime()调用的评论,我会得到以下内容:

在我看来,这就像一个bug,因为Sleep(2000)似乎从未发生过。

如果我将TimeTravelTo()的实现更改为使用类自身对Now的抽象:

代码语言:javascript
复制
/// <summary>
/// Move to the specific point in time provided.
/// </summary>
/// <param name="newDateTime">The point in time to move to.</param>
public void TimeTravelTo(DateTime newDateTime)
{
    Offset = newDateTime.Subtract(Now());
}

我明白了:

这对我来说更有意义(只要时间被冻结,Sleep(2000)就没有任何影响,但当您解除冻结时间时,偏移量又回到正轨上了)--但我可能错了,您的实现很可能正在做它应该做的事情。因此,我的观点不一定是您的代码中存在错误,而是您的XML文档应该更清楚地说明这种行为:解冻时间是否应该赶上实际的日期/时间?

票数 3
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/48100

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档