Are there any major flaws to implement this test helper function?
I know that the preferred way (refactoring) would simply make the function to be tested return its value and delegate printing to another part, but sometimes one has to test what is there.
import (
"io"
"os"
)
// captureStdout calls a function f and returns its stdout side-effect as string
func captureStdout(f func()) string {
// return to original state afterwards
// note: defer evaluates (and saves) function ARGUMENT values at definition
// time, so the original value of os.Stdout is preserved before it is changed
// further into this function.
defer func(orig *os.File) {
os.Stdout = orig
}(os.Stdout)
r, w, _ := os.Pipe()
os.Stdout = w
f()
w.Close()
out, _ := io.ReadAll(r)
return string(out)
}
Motivational full example
main.go
package main
import "fmt"
func main() {
fmt.Println("Hello, World!")
}
main_test.go
package main
import (
"io"
"os"
"testing"
)
func Test_main(t *testing.T) {
want := "Hello, World!\n"
got := captureStdout(main)
if got != want {
t.Errorf("main() = %v, want %v", got, want)
}
}
// captureStdout calls a function f and returns its stdout side-effect as string
func captureStdout(f func()) string {
// return to original state afterwards
// note: defer evaluates (and saves) function ARGUMENT values at definition
// time, so the original value of os.Stdout is preserved before it is
// changed further into this function.
defer func(orig *os.File) {
os.Stdout = orig
}(os.Stdout)
r, w, _ := os.Pipe()
os.Stdout = w
f()
w.Close()
out, _ := io.ReadAll(r)
return string(out)
}