Testing Techniques
Why Stack Overflow recommends it
Stack Overflow users link it when answering Go testing questions, especially how to test os.Exit paths, fake time, and verify that a function was called.
Recommended by 3 people across 3 different months, 2014 to 2017.
What it is
A 50-minute talk by Go team member Andrew Gerrand on practical techniques for testing Go programs, covering the testing package, table-driven tests, faking functions and time, and testing code that calls os.Exit. This recording is from a July 2014 golang-syd meetup, originally given at Google I/O 2014, with slides and demo code linked.
What people said
Recommends Timo Reimann · 2015-10 · Stack Overflow · on “How to test os.exit scenarios in Go”
There's a presentation [LINK] by Andrew Gerrand (one of the core members of the Go team) where he shows how to do it. Given a function (in main.go ) package main import ( "fmt" "os" ) func Crasher() { fmt.Println("Going down in flames!") os.Exit(1) } here's how you would test it (through main_test.go ): package main import ( "os" "os/exec" "testing" ) func TestCrasher(t *testing.T) { if os.Getenv("BE_CRASHER") == "1" { Crasher() return } cmd := exec.Command(os.Args[0], "-test.run=TestCrasher") cmd.Env = append(os.Environ(), "BE_CRASHER=1") err := cmd.Run() if e, ok := err.(*exec.ExitError); ok && !e.Success() { return } t.Fatalf("process ran with err %v, want exit status 1", err) } What the
Recommends Ainar-G · 2016-09 · Stack Overflow · on “Golang testing programs that involves time”
This was actually answered in Andrew Gerrand's Testing Techniques talk [this video] . In your code do var ( timeNow = time.Now timeAfter = time.After ) // ... type Obj struct{} func (o Obj) TimeCriticalFunc(d time.Duration) bool { // Call timeAfter and timeNow. } And in your tests do func TestTimeCriticalFunc(t *testing.T) { timeNow = func() time.Time { return myTime // Some time that you need } // "Redefine" timeAfter etc. if !Obj{}.TimeCriticalFunc(10 * 24 * time.Hour) { t.Fail() } }
Recommends adamliesko · 2017-09 · Stack Overflow · on “assert_called_once() or assert_called_xyz().... equivalent?”
I've used the approach of counter on the struct and then asserting it inside the package level unit test multiple times in the past. Still, it's probably only until the level of package, when you would like to test such an internal assertions. I believe it's an accepted way of doing this in Go. Just be careful about properly synchronizing the access to the counter, if you decide to use a global variable or run the tests concurrently. package main import ( "fmt" "sync" "testing" ) type fakeable interface { Hello() } type fakeFarmService struct { mu sync.Mutex counter int } func (f *fakeFarmService) Hello() { f.mu.Lock() f.counter++ f.mu.Unlock() } func helloCaller(callee fakeable) { callee.He
Cites Amer · 2014-09 · Stack Overflow · on “How to generate unit test coverage when using command line flags in Golang subprocess testing?”
I have unit tests for most of our code. But I cannot figure out how to generate unit tests coverage for certain code in main() in main package. The main function is pretty simple. It is basically a select block. It reads flags, then either call another function/execute something, or simply print help on screen. However, if commandline options are not set correctly, it will exit with various error codes. Hence, the need for sub-process testing. I tried sub-process testing technique but modified code so that it include flag for coverage: cmd := exec.Command(os.Args[0], "-test.run=TestMain -test.coverprofile=/vagrant/ucover/coverage2.out") Here is original code: [LINK] Explanation of above slid
Cites Ainar-G · 2014-09 · Stack Overflow · on “Simplifying Go Code”
Since Go doesn't encourage overloaading methods, is the redundancy acceptable? Or should I refactor them into one function? The answer to your question depends heavily on the real code and your task. If listing one customer is very different from listing several customers (that is, you need different information and have different presentation logic), I'd say that duplication here is not that bad, since the difference may grow larger in the future, so a DRY solution could turn into an if and switch mess quickly. (I've had a similar experience on a non-Go project and since then I think that DRY is good but you should not be fanatic about it.) On the other hand, if you're making, say a JSON AP
Cites Ainar-G · 2015-01 · Stack Overflow · on “How to test call expectation in Go”
You could make a function out of your method like this: var sendToServer = (*Server).Send func func (d *MyClass) SendToServer(args) { // ... sendToServer(server, msg) // ... } And in your tests: func TestMyClass_SendToServer(t *testing.T) { // ... sent := false sendToServer = func(*Server, args) { sent = true } mc.SendToServer(args) if !sent { t.Error("fail") } } This is described in Andrew Gerrand's Testing Techniques talk [this video] .
Cites Ainar-G · 2015-09 · Stack Overflow · on “How to verify if a specific function is called”
You can fake the whole deal with interfaces, but you could also use fakeable functions. In the code: var cmdStart = (*exec.Cmd).Start func (f *Feature) Start() error { cmd := exec.Command(f.Cmd) return cmdStart(cmd) } In the tests: called := false cmdStart = func(*exec.Cmd) error { called = true; return nil } f.Start() if !called { t.Errorf("command didn't start") } See also: Andrew Gerrand's Testing Techniques talk [this video] .