Go の 構造体のタグを取得する
備忘録。
json などで構造体のフィールドに付ける json:omitempty
などのタグを取得する方法について。
構造体フィールドのタグは標準パッケージ reflect
を使って実行時に取得する。
以下、構造体 Tagged
のフィールド Foo
に付いているタグを取得するサンプル。
package main import ( "fmt" "reflect" ) type Tagged struct { Foo string `tagA:"aaa" tagB:"bbb,ccc"` } func main() { var tagged Tagged // 型情報を取得 var t reflect.Type = reflect.TypeOf(tagged) // Foo のフィールド情報を取得 var f reflect.StructField var ok bool f, ok = t.FieldByName("Foo") if !ok { panic("Foo is not found") } // Foo のタグを取得 var tag reflect.StructTag tag = f.Tag // tagA の値を取得 fmt.Printf("tagA: %#v\n", tag.Get("tagA")) // => "aaa" // tagB の値を取得 fmt.Printf("tagB: %#v\n", tag.Get("tagB")) // => "aaa" // 存在しないタグに対しては空文字列を返す fmt.Printf("tagC: %#v\n", tag.Get("tagC")) // => "" // Lookup を使うと存在判定ができる _, ok = tag.Lookup("tagC") fmt.Printf("tagC exists: %#v\n", ok) }
t.Run で Go のテストをサブテストに分割する
備忘録。
Go のテスト関数内でサブテストに分割する方法について。
testing.T
は Error
や Skip
などのように関数で実装しているテストの制御を行うメソッドがあるが、サブテストに分割するためのメソッド Run
も実装されている。以下のように使える:
func TestFoo(t *testing.T) { t.Run("Sub Test 1", func (t *testing.T) { if foo(1, 2) != 42 { t.Error("foo(1, 2) is not 42") } }) }
第1引数にサブテストの名前、第2引数にサブテストの内容を関数で渡す。
これは Table Driven Test で書く場合に有効である。
for i, tt := range cases { // テストケースごとにサブテストにする t.Run(fmt.Sprintf("case %d", i), func (t *testing.T) { ... }) }
これは t.Run
を使わない場合と比べて以下のメリットがある
- 必要に応じて各ケースに名前をつけられる
- 独立したテストになるので、どのケースが成功してどのケースが失敗したかがわかりやすい