How to test a function's output (stdout/stderr) in unit tests
Solution 1
One thing to also remember, there's nothing stopping you from writing functions to avoid the boilerplate.
For example I have a command line app that uses log
and I wrote this function:
func captureOutput(f func()) string {
var buf bytes.Buffer
log.SetOutput(&buf)
f()
log.SetOutput(os.Stderr)
return buf.String()
}
Then used it like this:
output := captureOutput(func() {
client.RemoveCertificate("www.example.com")
})
assert.Equal(t, "removed certificate www.example.com\n", output)
Using this assert library: http://godoc.org/github.com/stretchr/testify/assert.
Solution 2
You can do one of three things. The first is to use Examples.
The package also runs and verifies example code. Example functions may include a concluding line comment that begins with "Output:" and is compared with the standard output of the function when the tests are run. (The comparison ignores leading and trailing space.) These are examples of an example:
func ExampleHello() {
fmt.Println("hello")
// Output: hello
}
The second (and more appropriate, IMO) is to use fake functions for your IO. In your code you do:
var myPrint = fmt.Print
func (t *Thing) print(min_verbosity int, message string) {
if t.verbosity >= minv {
myPrint(message) // N.B.
}
}
And in your tests:
func init() {
myPrint = fakePrint // fakePrint records everything it's supposed to print.
}
func Test...
The third is to use fmt.Fprintf
with an io.Writer
that is os.Stdout
in production code, but bytes.Buffer
in tests.
![Flimzy](https://i.stack.imgur.com/nrV9I.png?s=256&g=1)
Flimzy
I coach small teams to benefit from DevOps, without the Enterprise scale. Contact me on my web site, or read my blog. You can also find me at: GitHub GitLab LinkedIn Twitter YouTube I am the author of Kivik which provides a common interface to CouchDB and PouchDB for Go and GopherJS. I am a contributor to the Apache CouchDB project, and a member of the CouchDB PMC.
Updated on December 03, 2021Comments
-
Flimzy over 2 years
I have a simple function I want to test:
func (t *Thing) print(min_verbosity int, message string) { if t.verbosity >= minv { fmt.Print(message) } }
But how can I test what the function actually sends to standard output? Test::Output does what I want in Perl. I know I could write all my own boilerplate to do the same in Go (as described here):
orig = os.Stdout r,w,_ = os.Pipe() thing.print("Some message") var buf bytes.Buffer io.Copy(&buf, r) w.Close() os.Stdout = orig if(buf.String() != "Some message") { t.Error("Failure!") }
But that's a lot of extra work for every single test. I'm hoping there's a more standard way, or perhaps an abstraction library to handle this.