Go 1.16で追加されたiotest.ErrReaderを使ってio.Readerの異常系をテストする

commits1 min read読了の目安(約1200字

io.ReadAllなどの異常系をテストしたい

例えば次のio.Readerを受けて中身の文字列を返す関数をテストしたいとき、io.ReadAllerrを返させるのが難しいので異常系のテストが書きにくそうです。

read.go
import "io"

func read(r io.Reader) (string, error) {
	b, err := io.ReadAll(r)
	if err != nil {
		return "", err
	}

	return string(b), nil
}

iotest.ErrReaderを使えば出来る

Go 1.16から新しくtesting/iotestパッケージに追加されたiotest.ErrReaderを使えばio.Readerを伴う関数の異常系を簡単にテスト出来るようになりました。

read_test.go
import (
	"errors"
	"io"
	"strings"
	"testing"
	"testing/iotest"
)

func Test_read(t *testing.T) {
	t.Parallel()

	cases := map[string]struct {
		r     io.Reader
		str   string
		noErr bool
	}{
		"success": {
			r:     strings.NewReader("test"),
			str:   "test",
			noErr: true,
		},
		"failure": {
			r:     iotest.ErrReader(errors.New("test")),
			str:   "",
			noErr: false,
		},
	}

	for name, c := range cases {
		c := c
		t.Run(name, func(t *testing.T) {
			t.Parallel()

			str, err := read(c.r)

			if str != c.str {
				t.Errorf("want '%v', got '%v'", c.str, str)
			}
			if c.noErr {
				if err != nil {
					t.Error("want 'nil', got 'not nil'")
				}
			} else {
				if err == nil {
					t.Error("want 'not nil', got 'nil'")
				}
			}
		})
	}
}

カバレッジもバッチリです