🪵
slog.Info, slog.Errorなどの出力をテストする
はじめに
slog.Info
, slog.Warn
, slog.Error
などのslog.Default()
を用いてロギングする以下のような関数のテストを書く。
func myFunc() {
slog.Info("myFunc called", slog.String("key", "value"))
}
結論
このようなテストヘルパー関数を用いる。テストを並列実行する場合を考慮してロックを取る。
package testutil
var mu sync.Mutex
func CaptureSlog(t *testing.T, f func()) []byte {
t.Helper()
mu.Lock()
defer mu.Unlock()
original := slog.Default()
var buf bytes.Buffer
logger := slog.New(slog.NewJSONHandler(&buf, nil))
slog.SetDefault(logger)
defer slog.SetDefault(original)
f()
return buf.Bytes()
}
このように使う。
func myFunc() {
slog.Info("myFunc called", slog.String("key", "value"))
}
func TestMyFunc(t *testing.T) {
t.Parallel()
for i := range 2 {
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
t.Parallel()
logBytes := testutil.CaptureSlog(t, func() {
myFunc()
})
var m map[string]interface{}
if err := json.Unmarshal(logBytes, &m); err != nil {
t.Fatalf("json.Unmarshal() = %v; want nil", err)
}
if got, want := m["msg"], "myFunc called"; got != want {
t.Errorf("msg = %v; want %v", got, want)
}
if got, want := m["level"], slog.LevelInfo.String(); got != want {
t.Errorf("level = %v; want %v", got, want)
}
if got, want := m["key"], "value"; got != want {
t.Errorf("key = %v; want %v", got, want)
}
})
}
}
おわりに
testutil.CaptureSlog
を通さずにslog.SetDefault
が使われると並列実行時に落ちるので、そのあたりはLinterなどでチェックすると良い。
Discussion