正确的方法来测试使用time.Ticker的代码?

时间:2014-02-22 14:03:10

标签: go

我希望您就测试使用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

如果我想测试这个,我想提供一个模拟,这样我就可以快速,可预测地运行测试,所以我需要找到一种方法让我的模拟进入倒计时功能。

我可以想到几种方法:

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

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

如果我采用后一种方式,我是否透露了太多关于Countdown如何工作的信息,并使潜在客户更难以使用此代码?他们不必提供持续时间和间隔,而是必须构建并传递Ticker。

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

感谢您的帮助!

2 个答案:

答案 0 :(得分:3)

由于这是一个非常简单的函数,我假设您只是将它作为如何模拟非平凡事物的一个例子。如果你真的想测试这个代码,而不是模拟自动收报机,为什么不只是使用非常小的间隔。

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

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

答案 1 :(得分:0)

这并没有回答如何注入模拟部分,但似乎你在努力。 如果该示例代表您实际测试的内容,那么只需使用小数字。

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
}