LoginSignup
12
7

More than 3 years have passed since last update.

Goでログ出力/標準出力をテストする

Last updated at Posted at 2019-09-08

Goのlogパッケージや標準出力内容の結果をテストをしたいときのメモ。

ログ出力のテスト

Goのlogパッケージのlog.PrintXXのログ出力先はデフォルトではos.Stderrですが、log.SetOutputによって出力先を変更することができます。

log.SetOutput
func SetOutput(w io.Writer)

テストする関数は以下の通りです。

trysail.go
type member int

const (
    mocho member = iota
    sora
    nansu
)

func printLog(m member) {
    switch m {
    case mocho:
        log.Print("(o・∇・o)終わりだよ〜")
    case sora:
        log.Print("(°Q`)")
    case nansu:
        log.Print("(*>△<)<ナーンナーンっっ")
    }
}

引数によって出力するログの内容が変わる単純な関数です。

ではテストコードを書いてみましょう

trysail_test.go
func Test_printLog(t *testing.T) {
    // ログの出力先をバッファに変更
    var buf bytes.Buffer
    log.SetOutput(&buf)
    // デフォルトだと日付が出力されてしまうので、フラグに0を設定する
    defaultFlags := log.Flags()
    log.SetFlags(0)
    // Test_printLogテスト終了時、変更した内容を戻す
    defer func() {
        log.SetOutput(os.Stderr)
        log.SetFlags(defaultFlags)
    }()
    t.Run("Mocho", func(t *testing.T) {
        // 次のテスト(Nansu)に影響がないように、Mochoテスト終了時にバッファの内容をクリアする
        defer func() {
            buf.Reset()
        }()

        printLog(mocho)

        expected := "(o・∇・o)終わりだよ〜"
        // 末尾に改行コードが入っているので除去する
        actual := strings.TrimRight(buf.String(), "\n")
        if actual != expected {
            t.Fatalf("failed! actual = %s, expected = %s", actual, expected)
        }
    })
    t.Run("Nansu", func(t *testing.T) {
        defer func() {
            buf.Reset()
        }()

        printLog(nansu)

        expected := "(*>△<)<ナーンナーンっっ"
        actual := strings.TrimRight(buf.String(), "\n")
        if actual != expected {
            t.Fatalf("failed! actual = %s, expected = %s", actual, expected)
        }
    })
}

標準出力のテスト

なんと、Go言語の標準出力や標準入力であるos.Stdoutos.Stderros.Fileで上書きすることができます。マジかよ…

os.Filebytes.Bufferにつなぐためにos.Pipeを利用します。

テストする関数は以下の通りです。

trysail.go
type member int

const (
    mocho member = iota
    sora
    nansu
)

func print(m member) {
    switch m {
    case mocho:
        fmt.Println("(o・∇・o)終わりだよ〜")
    case sora:
        fmt.Println("(°Q`)")
    case nansu:
        fmt.Println("(*>△<)<ナーンナーンっっ")
    }
}

先ほどの関数のfmt.Println版です。
fmt.Printlnos.Stdoutに書き込むので、そちらをbytes.BufferにPipeします。

func Test_print(t *testing.T) {
    tmpStdout := os.Stdout
    defer func() {
        os.Stdout = tmpStdout
    }()
    t.Run("Mocho", func(t *testing.T) {
        r, w, _ := os.Pipe()
        os.Stdout = w

        print(mocho)
        w.Close() // クローズしないと永遠に読み込み待ち状態になるよ

        var buf bytes.Buffer
        buf.ReadFrom(r)

        expected := "(o・∇・o)終わりだよ〜"
        actual := strings.TrimRight(buf.String(), "\n")
        if actual != expected {
            t.Fatalf("failed! actual = %s, expected = %s", actual, expected)
        }
    })
    t.Run("Nansu", func(t *testing.T) {
        r, w, _ := os.Pipe()
        os.Stdout = w

        print(nansu)
        w.Close()

        var buf bytes.Buffer
        buf.ReadFrom(r)

        expected := "(*>△<)<ナーンナーンっっ"
        actual := strings.TrimRight(buf.String(), "\n")
        if actual != expected {
            t.Fatalf("failed! actual = %s, expected = %s", actual, expected)
        }
    })
}

意外と簡単にできた。
(o・∇・o)終わりだよ〜

12
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
7