I wondered what to do with Golang for tests involving the current time. I didn't get it right, so I made a library with only the functions I wanted.
@ tomtwinkle's article: [Golang] Create a testable current time acquisition process introduced the following three methods.
In addition, Kentaro Kawano's material was also helpful.
But, I hope it's easier like this. .. ..
I thought, I made a very thin library. https://github.com/bubusuke/xtime
It's the same as trying to do flextime and clock. You can wrap and replace time.Now (). But these two weren't quite right for me.
flextime is a little worrisome because it is exclusively controlled. (Also described in this article) Also, flextime has a long name (I want to shorten the coding). clock is a little worrisome because the name is too different from time.
Name: Time-like, but let's make it a short name. → xtime
Function: Aperture! → Only two.
Just use xtime.Now ()
.
~~ At the time of testing, just change the time with xtime.Mock (value returned by $ {xtime.Now ()})
. ~~
At the time of testing, just change the time with xtime.Mock (function executed by $ {xtime.Now ()})
.
How to use:
You can use it by replacing the part that uses time.Now () in the existing source with this.
xtime.Mock
from value to function for more flexibility. *git is open to the public, but the source is also posted below.
Source
xtime.go
package xtime
import (
"time"
)
var now func() time.Time = time.Now
// Mock overwrites return value of xtime.Now().
// You must not use this function except for in test.
func Mock(fn func() time.Time) {
now = fn
}
// Now returns the value of time.Now().
// If the Mock function has been executed in advance, the value set by Mock is returned.
func Now() time.Time {
return now()
}
test
xtime_test.go
package xtime_test
import (
"testing"
"time"
"xtime"
)
type incrementalMock struct {
i time.Duration
t time.Time
}
func (m *incrementalMock) Now() time.Time {
m.i++
return m.t.Add(time.Second * m.i)
}
func TestNow(t *testing.T) {
// case 1.
// Default xtime.Now behavior
// 'xtime.Now() == time.Now()' become false due to the μ second level execution time difference.
if !(xtime.Now().Sub(time.Now()) <= time.Second*1) {
t.Error("Default xtime.Now() must be same to time.Now().")
}
// case 2.
// Constant value Mock
mockTime := time.Date(2021, 1, 1, 0, 0, 0, 0, time.UTC)
xtime.Mock(func() time.Time { return mockTime })
if xtime.Now() != mockTime {
t.Error("xtime.Now() must be same to MockTime.")
}
// case 3.
// Incremental value Mock
incMock := &incrementalMock{
i: 0,
t: mockTime,
}
xtime.Mock(incMock.Now)
if xtime.Now().Sub(mockTime) != time.Second*1 {
t.Error("xtime.Now() must be same to MockTime+1sec.")
}
if xtime.Now().Sub(mockTime) != time.Second*2 {
t.Error("xtime.Now() must be same to MockTime+2sec.")
}
// case 4.
// reset
xtime.Mock(time.Now)
// Same to 1st test case.
if !(xtime.Now().Sub(time.Now()) <= time.Second*1) {
t.Error("Default xtime.Now() must be same to time.Now().")
}
}
Recommended Posts