Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/linq/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Unit testing 是否有一种简单的方法可以在测试期间全局剔除time.Now()?_Unit Testing_Go - Fatal编程技术网

Unit testing 是否有一种简单的方法可以在测试期间全局剔除time.Now()?

Unit testing 是否有一种简单的方法可以在测试期间全局剔除time.Now()?,unit-testing,go,Unit Testing,Go,我们的部分代码是时间敏感的,我们需要能够保留一些东西,然后在30-60秒内释放它,等等,我们只需执行time.Sleep(60*time.Second) 我刚刚实现了时间接口,在测试期间使用了时间接口的存根实现,类似于 然而,time.Now()在多个站点中被调用,这意味着我们需要传递一个变量来跟踪我们实际睡眠的时间 我想知道是否有另一种方法可以在全球范围内剔除time.Now()。也许通过系统调用来改变系统时钟 也许我们可以编写自己的时间包,它基本上围绕着时间包,但允许我们改变它 我们当前的实

我们的部分代码是时间敏感的,我们需要能够保留一些东西,然后在30-60秒内释放它,等等,我们只需执行
time.Sleep(60*time.Second)

我刚刚实现了时间接口,在测试期间使用了时间接口的存根实现,类似于

然而,
time.Now()
在多个站点中被调用,这意味着我们需要传递一个变量来跟踪我们实际睡眠的时间

我想知道是否有另一种方法可以在全球范围内剔除
time.Now()
。也许通过系统调用来改变系统时钟

也许我们可以编写自己的时间包,它基本上围绕着时间包,但允许我们改变它


我们当前的实现效果很好,我是一个新手,我很好奇是否有人有其他想法?

通过实现自定义界面,您已经走上了正确的道路。我认为您使用了您发布的golang nuts线程中的以下建议:


类型时钟接口{
时间到了,时间到了

在(d time.Duration)之后,如果您只需要存根
time。现在,您可以将依赖项作为函数注入,例如

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)
如果你来自动态语言背景(例如Ruby),那么这一切都有点难看:(

我使用来替换
时间。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())
}

这在冒充系统依赖关系的测试中非常有效,避免了错误。生产代码与测试代码保持分离,您可以获得对系统依赖关系的有用控制。

如果需要模拟的方法很少,例如
Now()
,您可以创建一个包变量,该变量可以被测试覆盖:

package foo

import "time"

var Now = time.Now

// The rest of your code...which calls Now() instead of time.Now()
然后在测试文件中:

package foo

import (
    "testing"
    "time"
)

var Now = func() time.Time { return ... }

// Your tests

从谷歌搜索结果中,我找到了相对简单的解决方案:

基本思想是使用另一个函数调用“nowFunc”来获取时间。Now()。
在main中,初始化此函数以返回time.Now()。在测试中,初始化此函数以返回固定的假时间。

有多种方法可以模拟或存根时间。测试代码中的Now():

  • 将时间实例传递给函数
  • 将生成器传递给函数
  • 带有接口的摘要
  • 包级时间发生器功能
  • 在结构中嵌入时间生成器
每个都有自己的加号和减号。最好的方法是将生成时间的函数和使用时间的处理部分分开


这篇文章详细介绍了它,并提供了一个示例,使具有时间依赖性的函数易于测试。

我们已经公开了一个库,我们一直在内部使用该库:

它提供了与本机
time
包相同的API,但是可以在运行时从测试中替换实现


它是@Flimzy之前提出的解决方案的组合。

我们可以存根时间。现在只需使用go包“github.com/undefinedlabs/go mpatch”

导入go-mpatch包,并将下面的代码片段放在代码中需要存根时间的任何位置。现在()

根据需要替换时间、日期的值

签出示例代码以检查go mpatch的工作情况


@stephanos您应该将此作为单独的答案发布,因为很容易错过。此外,回购协议本身的使用示例也会很有用。这样做的缺点是,如果用例需要多次,我们需要为每次创建一个结构。示例
MiddNightClock
在午夜返回时间,
christmass2015Clock
返回特定的时间注释:您不必现在就公开它,以便在测试中访问。我喜欢这个解决方案;但是有什么问题吗
var Now=
?为什么在这里使用函数?@IvanAracki:我不理解您的问题。如果您想删除函数,您必须使用函数。因为时间不断变化,所以它会被删除必须是函数。如果定义重复,它只会使用重复的定义创建错误。不要这样做。尽可能避免使用
init
。这里绝对没有理由使用init。在这种情况下,
init
所做的只是掩盖编码错误,并可能引入其他副作用(因为您现在已经替换了
——任何依赖于旧行为的行为现在都可能被破坏)。我也在使用这种方法,但不知道这种方法是否有任何缺点。好处是它避免了传递
时钟接口。注意:你不应该在产品中使用这个库,因为它有许可证,你不应该在生产中这样做,而不管许可证是什么。@AllenLuce这就是为什么许可证看起来是这样的吗s?看起来很有敌意license@Rambatino我没有写许可证,所以我不能给你一个真正的答案。有很多与许可证无关的原因将其排除在生产代码之外:它与内联线不兼容,并且不是线程安全的。重新定义库函数可能会让以后不得不处理你的混乱的人感到困惑在测试环境中明智地使用此软件包可以使您的生产代码比此问题的答案中描述的任何其他技术都更简单。我知道所有这些-但是“我不允许任何人出于任何目的使用此工具”-这不意味着不要将其用于测试吗?这只是让我困惑,为什么它会包含在一个明确发布供人们使用的包中?
package foo

import "time"

var Now = time.Now

// The rest of your code...which calls Now() instead of time.Now()
package foo

import (
    "testing"
    "time"
)

var Now = func() time.Time { return ... }

// Your tests
func CheckEndOfMonth(now time.Time) {
  ...
}
CheckEndOfMonth(now func() time.Time) {
    // ...
    x := now()
}
type Clock interface {
    Now() time.Time
}

type realClock struct {}
func (realClock) Now() time.Time { return time.Now() }

func main() {
    CheckEndOfMonth(realClock{})
}
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
}
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()
}
 mpatch.PatchMethod(time.Now, func() time.Time {
    return time.Date(2020, 11, 01, 00, 00, 00, 0, time.UTC)
})