🦔
Type switchesの使い所
初めに
以前、testの実装でメソッドをmock化しようとした時に、
返り値にinterface型の値を返す(正確にいうと、参照渡しで渡された値に、返り値を入れて返す)
メソッドのmockを実装した際に少し詰まった。
その際にType switchesを使用して解決したのでメモとして残しておく。
前提
テストでmock化したかったのは下記実装のRun
メソッド
引数で受け取ったresに任意の値を入れて返すということをやりたかった。
package gqlclient
import (
"context"
"github.com/machinebox/graphql"
)
type GQLClient interface {
Run(ctx context.Context, query string, vars map[string]interface{}, res interface{}) error
}
type gqlClient struct {
client *graphql.Client
}
func New(endpoint string) GQLClient {
return &gqlClient{
client: graphql.NewClient(endpoint),
}
}
func (c *gqlClient) Run(
ctx context.Context,
query string,
vars map[string]interface{},
res interface{},
) error {
req := graphql.NewRequest(query)
for k, v := range vars {
req.Var(k, v)
}
if err := c.client.Run(ctx, req, &res); err != nil {
return err
}
return nil
}
実装
引数res
はどんなクエリの型でも受け取れるように、interface型で定義されている。
このようなとき、res
がHoge
という形であればHoge
に対して返り値を代入してあげるという処理が必要。
このような時にType switches
を使って実装した。
Type switches
interface型の値i
の型がint型だった場合は、1を代入し、string型の場合は"string"
を代入できる。
switch v := i.(type) {
case int:
v = 1
case string:
v = "string"
}
mockしたコード
package gqlclient
import (
"context"
)
type IDResponse struct {
ID int `json:"id"`
}
type Model struct {
ID IDResponse `json:"sidecar"`
}
type CreateResponse struct {
Model IDResponse `json:"sidecar"`
}
type gqlClientMock struct{}
func NewMock() *gqlClientMock {
return new(gqlClientMock)
}
func (c *gqlClientMock) Run(
ctx context.Context,
query string,
vars map[string]interface{},
res interface{},
) error {
switch v := res.(type) {
case *CreateResponse:
v.Model.ID = 1
}
return nil
}
所感
interface型の値であっても、型安全に値を扱うことができ、非常に便利だと感じた。
普段TypeScriptをよく書くが、同じような書き方はないので勉強になった。
Discussion