代码之家  ›  专栏  ›  技术社区  ›  mezoid

有可能在单元测试中模拟时间吗?

  •  4
  • mezoid  · 技术社区  · 15 年前

    this 问题…我正在尝试对以下场景进行单元测试:

    不幸的是,我能想到的测试它的唯一方法,就是用秒表计时…它有两个副作用。。。

    1. 执行测试需要3秒钟…我通常喜欢以毫秒为单位运行测试
    2. 运行测试的时间变化+/-10ms左右,这可能会导致测试失败,除非我将此变化考虑在内。

    如果有一种方法可以模拟这种对时间的依赖,这样我的测试就可以运行得更快,并且结果也相当一致,那就更好了。不幸的是,我想不出一个办法来解决这个问题……所以我想问问你们是否有人遇到过这个问题。。。

    5 回复  |  直到 8 年前
        1
  •  8
  •   Matthew Scharley    15 年前

    你可以做一个 Waiter 类,该类提供方法, Wait(int) 等待指定时间量的。对这个方法进行测试,然后在单元测试中,传入一个模拟版本,该版本只跟踪请求等待的时间,但立即返回。

    例如(C#):

    interface IWaiter
    {
        void Wait(int milliseconds);
    }
    
    class Waiter : IWaiter
    {
        public void Wait(int milliseconds)
        {
            // not accurate, but for the sake of simplicity:
            Thread.Sleep(milliseconds);
        }
    }
    
    class MockedWaiter : IWaiter
    {
        public void Wait(int milliseconds)
        {
            WaitedTime += milliseconds;
        }
        public int WaitedTime { get; private set; }
    }
    
        2
  •  4
  •   ndp    15 年前

    诀窍是创建时间提供者的模拟。

    Time.expected(:now).returns(now).once 等

    interface Clock {
      Date getNow();
    }
    

    public String elapsedTime(Date d) {
      final Date now = new Date();
      final long ms = now.getTime() - d.getTime();
      return "" + ms / 1000 + " seconds ago";
    }
    

    作为:

    public String elapsedTime(Date d, Clock clock) {
      final Date now = clock.getNow();
      final long ms = now.getTime() - d.getTime();
      return "" + ms / 1000 + " seconds ago";
    }
    

    显然,时钟可以通过其他方式注入,但现在我们有了一种可测试和可扩展的方法。

        3
  •  2
  •   codingfloor    15 年前

    我经常这样测试重试尝试。我使用的方法是使超时可配置-然后我可以在测试中将其设置为零。在您的例子中,您可以模拟调用对象DoSomething(),期望对其进行3次调用,并将超时设置为0秒-然后您可以验证DoSomething()是否立即被调用3次。

        4
  •  2
  •   Len Holgate    14 年前
        5
  •  1
  •   Steve Freeman    15 年前

    你的直觉是正确的。诀窍是将问题的不同部分分开,而不是将它们捆绑到一个类中。您需要一个实现与时间无关的DoSomething的Action对象;一个Retryer对象,用于管理调用Action对象的尝试;还有一个等待的时钟。您可以直接对Action对象进行单元测试,使用stubbed Clock和Action对象对Retryer进行单元测试,并使时钟简单到可以正常工作。

    最重要的是,不要把真正的睡眠放在测试中,它只是太脆弱和缓慢。