LoginSignup
4
4

More than 5 years have passed since last update.

Go 製コマンドラインツールの Stdin, Stdout, Stderr をテストする

Posted at

コマンドラインツールを作成すると、Stdin,Stdout,Stderr を扱うときがあって、それらのテストをやろうとした時どうすればいいのか考えますよね。
今回もツールを作っててハマったので記録しておきます。

構造体に io.Reader, io.Writer を定義する

例えば

person.go
type Person struct {
    Stdin     io.Reader
    Stdout    io.Writer
    Stderr    io.Writer
}

func New() *Person {
    return &Person{
        Stdin:  os.Stdin,
        Stdout: os.Stdout,
        Stderr: os.Stderr,
    }
}

のような感じで構造体に定義しておきます。
こうすることで、

person := person.New()

のようなコードを書いたとして標準入力なら

scanner := bufio.NewScanner(person.Stdin)

標準出力なら

person.Stdout.Write([]byte("Hello"))

といったコードを書くことができます。

テストを書く

上記のような構造体を使うことで、Stdin,Stdout,Stderr のテストを次のように行うことができます。ポイントはそのまま os.Stdin, os.Stdout, os.Stderr を使うのではなく、別の io.Reader, io.Writer に置き換えることでテストが可能になります。
この時、bytes.Buffer を使うと便利です。

person_test.go

import (
    "fmt"
    "bytes"
    "scanner"
    "testing"
)

func TestPerson(t *testing.T) {
    // 別の io.Reader, io.Writer に置き換える
    expected := "Hello"
    input := bytes.NewBufferString(expected + "\n")
    output := new(bytes.Buffer)
    person := &Person{
        Stdin:  input,
        Stdout: output,
        Stderr: output,
    }

    // standard output
    fmt.Fprint(person.Stdout, expected)
    if expected != output.String() {
        t.Errorf("got: %s, expected: %s", output.String(), expected)
    }

    // standard input
    scanner := bufio.NewScanner(person.Stdin)
    for scanner.Scan() {
        text := scanner.Text()
        if expected != text {
            t.Errorf("got: %s, expected: %s", text, expected)
        }
    }
}

stdout では fmt.Fprint()person.Stdout に書き込んだ文字列を output 変数を通じて取り出しています。output.String()
stdin では bytes.NewBufferString() で書き込んだ文字列を scanner := bufio.NewScanner(person.Stdin) から scanner.Text() を通じて取得しています。

今回はこのような感じでテストしました。
間違っているところや直した方ががいいポイントがあれば、是非教えてください!!

4
4
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
4
4