Golang で標準出力をテストする

はじめに

Golang で fmt.Printf などの標準出力結果をテストしたい場合、出力をキャプチャすることでテストが可能になります。

標準出力するプログラム

例として物凄く単純な標準出力するだけの関数を用意します。

func print(str string) {
    fmt.Printf("%s", str)
}

出力のキャプチャ

出力をキャプチャするには出力先を一時的に切替て、出力結果を値として取得することで実現可能です。
fmt.Printf の出力先である os.Stdout の型は *os.File です。
*os.File で出力を受けて、値を取得するには os.Pipe() が役に立ちます。
os.Pipe() は戻り値として writerreader が取得できます。

つまり出力先を os.Stdout から writer に切り替えて、 reader から値を取得することでキャプチャが可能となります。

それではテストコードを見ていきましょう。

テストコード

func TestPrint(t *testing.T) {
    r, w, err := os.Pipe()
    if err != nil {
        t.Fatal(err)
    }
    stdout := os.Stdout
    os.Stdout = w

    print("hoge")

    os.Stdout = stdout
    w.Close()

    var buf bytes.Buffer
    io.Copy(&buf, r)

    if buf.String() != "hoge" {
        t.Errorf("print() = %s, want hoge", buf.String())
    }
}

順を追って説明しましょう。

r, w, err := os.Pipe()
if err != nil {
    t.Fatal(err)
}
stdout := os.Stdout
os.Stdout = w

まずテストする関数を呼び出す前に os.Pipe()readerwriter を生成します。
そして 標準出力の出力先を os.Stdout から writer に切り替えます。

print("hoge")

os.Stdout = stdout
w.Close()

次に関数を実行したら出力先を元の os.Stdout に戻します。
writer もクローズします。

var buf bytes.Buffer
io.Copy(&buf, r)

最後に readerから buffer へ値を渡します。

まとめ

Golang で標準出力をテストする場合は os.Pipe() を駆使して出力先を切り替えて値をキャプチャしましょう。