Hi! First time writing a post here. Hope you enjoy!
Introduction
It's quite common the needing to test some function from a standard library package. Today, I want to show you guys one simple way for testing some troublesome functions, such as time.Now
, which I'm gonna use for this tutorial.
Hum, go on...
There are a few ways of doing that, one of them is injecting your target function (the one you want to mock, the time.Now
in my case) in the function you are testing, just pass it as a parameter.
package main
import (
"fmt"
"time"
)
func WhatTimeIsIt(nowFunc func() time.Time) {
fmt.Printf("The time is now: %v\n", nowFunc())
}
func main() {
WhatTimeIsIt(time.Now)
// So, when testing you could do something like this
mockedNowFunc := func() time.Time {
// I can control the time with one line of code, mwhahaha
return time.Date(2050, time.January, 01, 15, 06, 54, 0, &time.Location{})
}
WhatTimeIsIt(mockedNowFunc)
}
// outputs
// The time is now: 2020-06-16 21:44:35.722303193 -0300 -03 m=+0.000060729
// The time is now: 2050-01-01 15:06:54 +0000 UTC
The problem with that is you need to pass the original Now
function every time you want to know WhatTimeIsIt
in production code :/
Of course this won't cause you a production bug, because Go Compiler is awesome and would warn you if you
forget a parameter when calling the function, but, it's still kind of annoying injecting it every time. It should have a way to avoid this...
YES, my young apprendice, there is. That's why I'm writing this post
It's very simple, actually, you just need to wrap your original function inside a global variable within your package... Wait, what?!
I'm gonna show you and you'll probably think: Why the hell did he write this post, then? ¯_(ツ)_/¯ Everyone needs to start somewhere, right?!
package main
import (
"fmt"
"time"
)
func WhatTimeIsIt() {
fmt.Printf("The time is now: %v\n", nowFunc())
}
var nowFunc = func() time.Time {
return time.Now()
}
func main() {
WhatTimeIsIt()
// So, when testing you could do something like this
nowFunc = func() time.Time { // note that we just overwrote the global var nowFunc
// I can control the time with one line of code, mwhahaha
return time.Date(2050, time.January, 01, 15, 06, 54, 0, &time.Location{})
}
WhatTimeIsIt()
}
// output still the same
// The time is now: 2020-06-16 21:44:35.722303193 -0300 -03 m=+0.000060729
// The time is now: 2050-01-01 15:06:54 +0000 UTC
Now you don't need to pass the function every time, and when you need to mock the function for testing, or whatever reason, you can just overwrite the nowFunc
var.
It's a nice tool for having in your toolkit. Probably, there are some other ways of doing that, but that's it for today.
Feel free to comment and thanks for reading!
Top comments (2)
Awesome, thanks for sharing. This pattern is indeed very useful in countless situations.
congratulations for the excellent post. Thanks, Douglas, for posting this!