goroutineのテストを同期的に行う
とある関数の評価値 ― 例えばファイルに文字列を書き込む ― をテストしたい場合、 その評価がgoroutine内だと、テスト側から実行しても、タイミングによって取得できないことがあります。 そこで、テスト側から評価するときにはchanelを渡す用にして、そのchanelに対して書き込むようにすることで同期処理できるようになります。
type SUTType struct { ... Out io.WriteCloser ... } func (o *SUTType) SUT() { ... go func() { o.Out.Write("aqours") }() ... }
テスト対象がこんな感じのコードになってたりする。
のでこの、 Out
をすげ替えてあげればいい。
func TestSUT(t *testing.T) { s := &SUTType{Out: &DummyOut{}} s.SUT() donewait := make(chan struct{}{}) var result string go func() { result := <-out.Buf donewait <- struct{}{} }() <-donewait if result != "aqours" { t.Error("should be aqours") } } type DummyOut struct { Buf chan []byte } func (o *DummyOut) Write(p []byte) (int, error) { o.Buf <- p return 0, nil } func (o *DummyOut) Close() error { return nil }
chanelを使うことで同期処理が可能になる、ということと、テスト可能なコードにする場合は、
インタフェースを持つことでテスト側で柔軟なコード ― 上記の例だと、 SUTType
のOutの型が os.File
だと途端にテストが面倒になる ―
にできる典型例でした。