#Pipeを駆使してスタブする
結論をここに載せておきます。
https://play.golang.org/p/JtIHncxhGw
##こんな感じの関数をテストしたい!って時です。
https://golang.org/pkg/bufio/#example_Scanner_lines
//標準入力を行番号付きで標準出力に出力する。refer to https://golang.org/pkg/bufio/#example_Scanner_lines
func hoge() {
i := 0
scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
i++
fmt.Println(i, scanner.Text()) // Println will add back the final '\n'
}
if err := scanner.Err(); err != nil {
fmt.Fprintln(os.Stderr, "reading standard input:", err)
}
}
##こんな感じで書きます。
入力、出力、エラー出力をそれぞれパイプで乗っ取って、対象を実行した後、元に戻して終了。
func TestHoge() {
strout, _ := StubIO("私が標準入力だ\nガハハ", func() {
hoge()
})
fmt.Println("キャプチャした標準出力")
fmt.Println(strout)
}
// StubIO stubs Stdin Stdout Stderr in 'fn'.return Stdout and Stderr
func StubIO(inbuf string, fn func()) (string, string) {
inr, inw, _ := os.Pipe()
outr, outw, _ := os.Pipe()
errr, errw, _ := os.Pipe()
orgStdin := os.Stdin
orgStdout := os.Stdout
orgStderr := os.Stderr
inw.Write([]byte(inbuf))
inw.Close()
os.Stdin = inr
os.Stdout = outw
os.Stderr = errw
fn()
os.Stdin = orgStdin
os.Stdout = orgStdout
os.Stderr = orgStderr
outw.Close()
outbuf, _ := ioutil.ReadAll(outr)
errw.Close()
errbuf, _ := ioutil.ReadAll(errr)
return string(outbuf), string(errbuf)
}
##コピペする前に
既にライブラリ化しましたので、ご自由に使ってください。
import(
"github.com/nak1114/goutil/assert"
)
func TestHoge() {
strout, _ := assert.StubIO("私が標準入力だ\nガハハ", func() {
hoge()
})
fmt.Println("キャプチャした標準出力")
fmt.Println(strout)
}
#Go言語はテスト関連が弱いですね。
自前主義ではないのだけど、Rubyで言うところのWebmockやFakeFSやTimeCopも見当たらないし、その他のスタブもあまり見かけませんね。
Webmock -> Mockサーバ立てろ
FakeFS -> 仮想環境でテストしろ
までは解るのですが、TimeCopはどうしろと。dockerの時間機能をゴニョゴニョするくらいしか思いつかないです。
とりあえず、私が必要と感じたものは逐次"github.com/nak1114/goutil"に追加していこうかなと思っています。
##テストフレームワークは結構好き
テスト対象と同じDirにテストを置いておくのは、行き来がしやすくて便利だと思いました。
##誰かアサーション作って!
テストレポートがいい加減になるからアサーションは提供しないよってのは、作りたくないだけですよね。これも自前で比較関数作るのダルいんだけど、私のググり力が足りないので既存のが見つからないんだよなぁ。Gospelも覗いてみたけどちょっと違う。