Golangの関数内で標準入力の値を受け取る関数に単体テストを行う方法をまとめました。
fmt.Scanで標準入力の値を受け取る関数
fmt.Scanを使用して標準入力から値を受け取る関数は、そのままだと単体テストができません。
下記のinputStdin関数は、関数内で標準入力の内容を受け取り
標準入力の内容をそのまま返す関数です。
1 2 3 4 5 6 7 |
func inputStdin() string { var inputValue string fmt.Println("入力してください") fmt.Print(">") fmt.Scan(&inputValue) return inputValue } |
inputStdinに単体テストを行うとエラーになります。
1 2 3 4 5 6 7 |
func TestInputStdin(t *testing.T) { got := inputStdin() want := "test" if got != want { t.Errorf("got %s, want %s", got, want) } } |
1 2 3 4 |
go test 入力してください >--- FAIL: TestInputStdin (0.00s) main_test.go:12: got , want test |
fmt.Scanの確認
fmt.Scanのコードを確認してみると、os.Stdinを第一引数に渡してFscanを呼び出しています。
1 2 3 |
func Scan(a ...any) (n int, err error) { return Fscan(os.Stdin, a...) } |
Fscanのコードを確認してみると、第一引数にio.Readerインターフェースの要件を満たす
型を渡すことができます。
引数rのio.Readerにos.Stdin以外の引数を渡すとテストできそうです。
1 2 3 4 5 6 |
func Fscan(r io.Reader, a ...any) (n int, err error) { s, old := newScanState(r, true, false) n, err = s.doScan(a) s.free(old) return } |
fmt.Fscanに書き換えて単体テスト
fmt.Scanだとos.Stdinから値を読み込んでしまうため、代わりにfmt.Fscanを使用し
任意のio.Readerから値を取得できるようにします。
1 2 3 4 5 6 7 8 9 10 11 12 |
func inputStdin2(in io.Reader) string { if in == nil { in = os.Stdin } var inputValue string fmt.Println("入力してください") fmt.Print(">") fmt.Fscan(in, &inputValue) return inputValue } |
1 |
func inputStdin2(in io.Reader) string { |
引数にio.Readerインターフェースの要件を満たすものを渡します。
1 2 3 |
if in == nil { in = os.Stdin } |
引数のinがnilのときはos.Stdinを入力に使用します。
1 |
fmt.Fscan(in, &inputValue) |
fmt.Scanの代わりにfmt.Fscanを使用し、第一引数にinを渡します。
第二引数に値を書き込みたい変数を渡します。
inputStdin2に単体テストを行ってみます。
1 2 3 4 5 6 7 8 |
func TestInputStdin2(t *testing.T) { in := bytes.NewBufferString("test") got := inputStdin2(in) want := "test" if got != want { t.Errorf("got %s, want %s", got, want) } } |
1 |
in := bytes.NewBufferString("test") |
bytes.NewBufferStringを利用してBuffer構造体を作成します。
Buffer構造体はio.Readerのインターフェース要件を満たしているため、inputStdin2の引数に渡すことができます。
テストを行うとokと表示されます。
1 2 3 4 |
go test 入力してください >PASS ok stdin-unittest 0.223s |
参考URL

fmtで学ぶ標準入力・出力|Goから学ぶI/O

How to write tests against user input in Go
How would I test against user input from fmt.Scan/Scanf/Scanln?For example how could I test that the function input will accept "4 5\n" and "1 2 3 4\n" from STD...
コメント