Goでtime.Now()を使用している箇所のテストについて

更新日:2025/3/13/(木) 12:38

タグ:Goテスト

概要

time.Now()を使用している箇所のテストがしづらいと感じたのでその際のメモ

結論:contextにtime.Now()で生成する方法を採用

既存のコード

func Hoge() { todo := GetTodo() if IsTimeAfter(todo.StartTime) { ... } } func IsTimeAfter(startTime time.Time) { currentDate := time.Now() // テストを実行する時刻に依存する。現在日時を固定にしたい。 return startTime.After(currentDate) }

対応方法

time.Now()で生成した現在時刻を引数にする

func Hoge() { todo := GetTodo() currentDate := time.Now() if IsTimeAfter(todo.StartTime, currentDate) { ... } } func IsTimeAfter(startTime, currentDate time.Time) { return startTime.After(currentDate) }

time.Now()で現在時刻を生成する処理をmock化

type TimeProvider interface { // インターフェースを作成 Now() time.Time } type RealTimeProvider struct{} func (rtp RealTimeProvider) Now() time.Time { // 実装 return time.Now() }
type SomeService struct { TimeProvider timeprovider.TimeProvider } func NewSomeService(tp timeprovider.TimeProvider) *SomeService { return &SomeService{TimeProvider: tp} } func (s *SomeService) Hoge() { currentDate := s.TimeProvider.Now() // テストの際はモックを使用する if IsTimeAfter(todo.StartTime, currentDate) { ... } } func IsTimeAfter(startTime, currentDate time.Time) { return startTime.After(currentDate) }

middlewareでtime.Now()で現在時刻を生成してcontextに入れておく

// middleware(echoを使用) func NewCurrentTime() echo.MiddlewareFunc { return func(next echo.HandlerFunc) echo.HandlerFunc { return func(c echo.Context) error { n := time.Now() ctx := context.WithValue(c.Request().Context(), "current_time", n) c.SetRequest(c.Request().WithContext(ctx)) return next(c) } } }
// route.go(echoを使用) func SetupRouter() *echo.Echo { e := echo.New() e.Use(middleware.NewCurrentTime()) // ここで使用 e.GET("/hoge", hogeHandler.Hoge) . .
func (s *SomeService) Hoge(ctx context.Context) { currentDate := ctx.Value("current_time").(time.Time) // ここでcontextから取得 if IsTimeAfter(todo.StartTime, currentDate) { ... } } // 現在時刻を引数にしているが、関数内でcontextから時刻を取得してもよい。迷う。 func IsTimeAfter(startTime, currentDate time.Time) { return startTime.After(currentDate) }

参考にした記事