How do I capture os.Stdout output into a string for testing purposes?

Issue

I have a function which produces output to os.Stdout that I would like to unit test. How can I capture the output into a string which I can compare in my unit tests?

  func f() {
       // How to capture "hello\n"?
      fmt.Fprintln(out, "hello")
  }

Solution

Classical Test Case Approach

Write your function to take an optional io.Writer which defaults to stdout, but lets you pass in an io.Writer. This will give you the ability to capture all output into a bytes.Buffer which can be used in the test cases.

  // f writes to stdout, or to an io.Writer if passed in.
  func f(fd ...io.Writer) {
      var out io.Writer
      switch len(fd) {
      case 0:
          out = os.Stdout
      case 1:
          out = fd[0]
      default:
          panic("called with too many parms")
      }
      fmt.Fprintln(out, "hello")
  }

When you call the function with no parameter, you get your usual expected operation of writing to stdout.

      f()       // Writes to stdout

For testing, pass a bytes.Buffer. When the function returns, the buffer will contain the output written by the function, ready for testing.

      var b bytes.Buffer  // capture output in b
      f(&b)

      fmt.Printf("<%s>\n", b.String())

An additional benefit of this approach is that the function can now easily write to a destination other than stdout if desired.

Playground: https://go.dev/play/p/3Kn_ht3ylE-

Answered By – Mark Harrison

Answer Checked By – Marilyn (GoLangFix Volunteer)

Leave a Reply

Your email address will not be published.