【问题标题】:Correct way to test code that uses time.Ticker?测试使用 time.Ticker 的代码的正确方法?
【发布时间】:2014-02-23 03:36:57
【问题描述】:

我希望您能就使用 time.Ticker 测试代码的正确方法提出建议

例如,假设我有一个如下所示的倒数计时器(只是我为解决这个问题而想出的一个例子):

type TickFunc func(d time.Duration)

func Countdown(duration time.Duration, interval time.Duration, tickCallback TickFunc) {
    ticker := time.NewTicker(interval)
    for remaining := duration; remaining >= 0; remaining -= interval {
        tickCallback(remaining)
        <-ticker.C
    }

    ticker.Stop()
 }

http://play.golang.org/p/WJisY52a5L

如果我想对此进行测试,我想提供一个模拟,以便我可以进行快速且可预测的测试,因此我需要找到一种方法让我的模拟进入 Countdown 函数。

我可以想到几种方法来做到这一点:

创建一个 Ticker 接口和一个包内部的第一类函数,我可以为测试目的打补丁:http://play.golang.org/p/oSGY75vl0U

创建一个 Ticker 接口并将实现直接传递给 Countdown 函数: http://play.golang.org/p/i67Ko5t4qk

如果我采用后一种方式,我是否会透露太多有关 Countdown 工作原理的信息,并让潜在客户更难使用此代码?他们必须构造并传入一个 Ticker,而不是给出一个持续时间和间隔。

我很想知道在测试这样的代码时最好的方法是什么?或者您将如何更改代码以保留行为,但使其更具可测试性?

感谢您的帮助!

【问题讨论】:

    标签: go


    【解决方案1】:

    由于这是一个非常简单的函数,我假设您只是将其用作如何模拟重要内容的示例。如果你真的想测试这段代码,而不是模拟代码,为什么不使用非常小的间隔。

    恕我直言,第二个选项是两者中的佼佼者,拨打用户电话:

    foo(dur, NewTicker(interval)... 
    

    似乎没有太大的负担。

    还有回调是 Go 中严重的代码异味:

    func Countdown(ticker Ticker, duration time.Duration) chan time.Duration {
        remainingCh := make(chan time.Duration, 1)
        go func(ticker Ticker, dur time.Duration, remainingCh chan time.Duration) {
            for remaining := duration; remaining >= 0; remaining -= ticker.Duration() {
                remainingCh <- remaining
                ticker.Tick()
            }
            ticker.Stop()
            close(remainingCh)
        }(ticker, duration, remainingCh)
        return remainingCh
    }
    

    然后您可以使用以下代码:

    func main() {
        for d := range Countdown(NewTicker(time.Second), time.Minute) {
            log.Printf("%v to go", d)
        }
    }
    

    在操场上:http://play.golang.org/p/US0psGOvvt

    【讨论】:

      【解决方案2】:

      这并没有回答如何注入模拟部分,但看起来你太努力了。 如果该示例代表您实际测试的内容,则只需使用小数字。

      http://play.golang.org/p/b_1kqyIu-u

      Countdown(5, 1, func(d time.Duration) {
              log.Printf("%v to go", d)
          })
      

      现在,如果您正在测试调用 Countdown 的代码(而不是测试 Countdown),那么我可能只是创建一个标志,您可以为您的模块设置一个标志,以便在相同的调用计数下尽可能快地缩放数字。

      http://play.golang.org/p/KqCGnaR3vc

      if testMode {
          duration = duration/interval
          interval = 1
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-06-06
        • 1970-01-01
        • 1970-01-01
        • 2023-03-10
        • 1970-01-01
        • 1970-01-01
        • 2020-11-27
        相关资源
        最近更新 更多