Mocking time in Go with go-mpatch

Sagar Sonwane
3 min readMar 11, 2021

While writing test cases, most of the golang developer must have struggled with mocking the value of time in their tests. The purpose of this blog is to address this problem with the help of a package i.e go-mpatch.

Let us understand how to mock time in your test cases using go-mpatch with the help of an example.

package mainimport (
"fmt"
"time"
)
//PrintTime method : returning string containing current time.
func PrintTime() string {
return fmt.Sprintf("Current Time Is %s: ", time.Now())
}
func main() { //printing returned string from PrintTime method
fmt.Println(PrintTime())
}

The above code consist of a method PrintTime() which returns a string containing current time.

output of above code

Just to look at the returned value, we are printing it in main method.

Now, let us look at the test case for the PrintTime() method without patching time.Now.

package mainimport (
"fmt"
"github.com/stretchr/testify/assert"
"testing"
"time"
)
//TestPrintCurrentTime method for testing PrintTime method
func TestPrintCurrentTime(t *testing.T) {
currTime := PrintTime()
assert.Equal(t, fmt.Sprintf("Current Time Is %s: ", time.Now()), currTime)
}

Now, let us look at the output when we run the test case.

Huhhhh….. Test are failing. But Why??.

Error is Expected value for time.Now() is different from Actual value of time.Now().

Reason is there is difference between the time when we are calling the method and the time when we are executing time.Now()to check the output. And this is a very common problem which developers encounter when they use time.Now() in their code and they use time.Now() in their test cases.

Now, to solve this problem “go-mpatch” comes to the rescue.
We will be using PatchMethod method from the package to patch time.Now method of time package.

package mainimport (
"fmt"
"github.com/stretchr/testify/assert"
"github.com/undefinedlabs/go-mpatch"
"testing"
"time"
)
func TestPrintCurrentTime(t *testing.T) {
mpatch.PatchMethod(time.Now, func() time.Time {
return time.Date(2020, 11, 01, 00, 00, 00, 0, time.UTC)
})
currTime := PrintTime()assert.Equal(t, fmt.Sprintf("Current Time Is %s: ", time.Now()), currTime)
}

The above code is similar to the one which we saw before, but we have now added a patch method to stub time.Now in our code.

PatchMethod method in “github.com/undefinedlabs/go-mpatch” package Patches a target func to redirect calls to “redirection” func. Both function must have same arguments and return types.

func PatchMethod(target, redirection interface{}) (*Patch, error)

Now lets look at the result of our test case.

Our test case passed, Ok. But did our patch method worked??.

Just to see how our patch worked, i added a couple of print statements in our test case, one printing time.Now() and other printing the returned value from PrintTime() method which we were testing.

As you can see in the above image, both the lines in output has same time, the time which we set in the patch method.

Noice. This means, our patch works like a charm.

I hope, this blog helped you with your query.
Thanks for reading :D.

--

--