我们的部分代码是时间敏感的,我们需要能够预留一些东西然后在30-60秒内释放它们,我们可以做一个 time.Sleep(60 * time.Second)
我刚刚实现了时间接口,并且在测试期间使用了时间接口的存根实现,类似于这个golang-nuts讨论.
然而,time.Now()在多个站点中调用,这意味着我们需要传递一个变量来跟踪我们实际睡了多少时间.
我想知道是否有另一种方法可以在time.Now()全球范围内存根.也许进行系统调用来改变系统时钟?
也许我们可以编写自己的时间包,它基本上包裹时间包但允许我们改变它?
我们目前的实施工作很好,我是一个初学者,我很想知道是否有人有其他想法?
nem*_*emo 41
通过实现自定义界面,您已经采用了正确的方式.我把它从你发布的golang坚果线程中使用以下建议:
type Clock interface {
Now() time.Time
After(d time.Duration) <-chan time.Time
}
Run Code Online (Sandbox Code Playgroud)
并提供具体的实施
type realClock struct{}
func (realClock) Now() time.Time { return time.Now() }
func (realClock) After(d time.Duration) <-chan time.Time { return time.After(d) }
Run Code Online (Sandbox Code Playgroud)
和测试实施.
在进行测试(或一般)时更改系统时间是一个坏主意.你不知道在执行测试时取决于系统时间的是什么,你不想通过花费数天的调试来找出困难的方法.只是不要这样做.
也没有办法在全局范围内影响时间包,这样做不会对接口解决方案做任何更多的事情.您可以编写自己的时间包,它使用标准库,并提供一个函数来切换到模拟时间库,以便测试是否需要传递时间对象以及困扰您的接口解决方案.
设计和测试代码的最佳方法可能是尽可能多地使代码无状态.在可测试的无状态部分中分离您的功能.单独测试这些组件要容易得多.此外,较少的副作用意味着使代码同时运行更容易.
All*_*uce 23
我使用bouk/monkey包来代替time.Now()我的代码中的假调用:
package main
import (
"fmt"
"time"
"github.com/bouk/monkey"
)
func main() {
wayback := time.Date(1974, time.May, 19, 1, 2, 3, 4, time.UTC)
patch := monkey.Patch(time.Now, func() time.Time { return wayback })
defer patch.Unpatch()
fmt.Printf("It is now %s\n", time.Now())
}
Run Code Online (Sandbox Code Playgroud)
这在测试中很有效,可以伪造系统依赖性并避免滥用的DI模式.生产代码与测试代码分开,您可以获得对系统依赖性的有用控制.
Fli*_*mzy 15
如果你需要模拟的方法很少,比如Now(),你可以创建一个可以被测试覆盖的包变量:
package foo
import "time"
var Now = time.Now
// The rest of your code...which calls Now() instead of time.Now()
Run Code Online (Sandbox Code Playgroud)
然后在你的测试文件中:
package foo
import (
"testing"
"time"
)
var Now = func() time.Time { return ... }
// Your tests
Run Code Online (Sandbox Code Playgroud)
有多种方法可以在测试代码中模拟或存根 time.Now() :
将时间实例传递给函数
func CheckEndOfMonth(now time.Time) {
...
}
Run Code Online (Sandbox Code Playgroud)
将生成器传递给函数
CheckEndOfMonth(now func() time.Time) {
// ...
x := now()
}
Run Code Online (Sandbox Code Playgroud)
带有接口的抽象
type Clock interface {
Now() time.Time
}
type realClock struct {}
func (realClock) Now() time.Time { return time.Now() }
func main() {
CheckEndOfMonth(realClock{})
}
Run Code Online (Sandbox Code Playgroud)
包级时间生成器函数
type nowFuncT func() time.Time
var nowFunc nowFuncT
func TestCheckEndOfMonth(t *Testing.T) {
nowFunc = func() time.Time {
return time.Now()
}
defer function() {
nowFunc = time.Now
}
// Test your code here
}
Run Code Online (Sandbox Code Playgroud)
在结构中嵌入时间生成器
type TimeValidator struct {
// .. your fields
clock func() time.Time
}
func (t TimeValidator) CheckEndOfMonth() {
x := t.now()
// ...
}
func (t TimeValidator) now() time.Time {
if t.clock == nil {
return time.Now() // default implementation which fall back to standard library
}
return t.clock()
}
Run Code Online (Sandbox Code Playgroud)
每个都有自己的优点和缺点。最好的方法是将生成时间的函数和使用时间的处理部分分开。
golang 中的 Stubbing Time帖子对此进行了详细介绍,并且有一个示例可以轻松测试具有时间依赖性的函数。
此外,如果你只需要存根,time.Now你可以将依赖作为一个函数注入,例如
func moonPhase(now func() time.Time) {
if now == nil {
now = time.Now
}
// use now()...
}
// Then dependent code uses just
moonPhase(nil)
// And tests inject own version
stubNow := func() time.Time { return time.Unix(1515151515, 0) }
moonPhase(stubNow)
Run Code Online (Sandbox Code Playgroud)
如果你来自动态语言背景(例如Ruby),那么这一切都有点难看:(
我们已经开源了一个我们一直在内部用于此目的的库:https : //github.com/cabify/timex
它提供与本机time包相同的 API,但可以在运行时从测试中替换实现。
这是@Flimzy 之前提出的解决方案的混合。
这与乔纳森·霍尔的答案相同,但我添加了一个具体的例子。
CurrentTime来包装time.now()CurrentTime函数,并使其返回所需的值。package main
import (
"fmt"
"time"
)
func main() {
fmt.Printf("This is the current year : %d ", GetCurrentYear())
}
// 'GetCurrentYear' function uses 'CurrentTime' function internally
func GetCurrentYear() int {
return CurrentTime().Year()
}
var CurrentTime = func() time.Time {
return time.Now()
}
Run Code Online (Sandbox Code Playgroud)
package main
import (
"testing"
"time"
. "gopkg.in/check.v1"
)
func Test(t *testing.T) { TestingT(t) }
type S struct{}
var _ = Suite(&S{})
func (s *S) TestCurrentYearShouldBeReturnedCorrectly(c *C) {
expectedYear := 2022
curentInstant := time.Date(expectedYear, 12, 01, 00, 00, 00, 0, time.UTC)
// Make 'CurrentTime' return hard-coded time in tests
CurrentTime = func() time.Time {
return curentInstant
}
c.Assert(GetCurrentYear(), Equals, expectedYear)
}
Run Code Online (Sandbox Code Playgroud)
这是Go Playground链接。
| 归档时间: |
|
| 查看次数: |
25177 次 |
| 最近记录: |