インターフェースに依存させてコードを書いてると、テストで具象型として扱いたいケースが出てきたので方法を調べた。
参考)
A Tour of Go
value := <インターフェース型の変数>.(<具象型>) value, ok := <インターフェース型の変数>.(<具象型>) // この場合okには成否が入る。
呼び方がいまいちわかってないが、
- [具象型 => 別の具象型(intからfloatとか)]:キャスト
- [インターフェース => 具象型]:型アサーション
という感じなのかな?
サンプルケース
Human構造体は言葉を覚えるMemoriseメソッドを持っている。
type Human struct { } func (h *Human) Memorise(word string) { // 覚える処理 }
本番運用時はDBに言葉を記録するが、テスト時はインメモリに保存したいので、
以下のようにPersistenceインターフェースを用意して、DIで切り替えられるようにした。
type Human struct { persistence Persistence } func (h *Human) Memorise(word string) { h.persistence.Save(word) } // インターフェース type Persistence interface { Save(word string) } // Dbに保存するPersistence type DbPersistence struct { // なんかdbに保存するためのプロパティなど } func (p *DbPersistence) Save(word string) { // dbに保存するための処理 } // memoryに保存するPersistence テスト用 type MemoryPersistence struct { memory []string } func (p *MemoryPersistence) Save(word string) { p.memory = append(p.memory, word) }
Memoriseテストの実行時、言葉を覚えているかをチェックするため以下のようにmemoryの内部を確認したい。
こんな感じで型アサーションする。
func Test_SomeTest(t *testing.T) { masao := Human{ persistence: &MemoryPersistence{}, } masao.Memorise("人に厳しく自分に甘く") // persisitenceはPersistenceインターフェース型だからmemoryにアクセスできない。コンパイルエラーになる if masao.persistence.memory[0] != "人に厳しく自分に甘く"{ t.Errorf("正しく覚えてない") } // こうやって型アサーションしてMemoryPersistence型として扱えばmemoryにアクセスできる。 memoryPersistence := masao.persistence.(*MemoryPersistence) if memoryPersistence.memory[0] != "人に厳しく自分に甘く" { t.Errorf("正しく覚えてない") } }